Index: stable/10/sys/arm/broadcom/bcm2835/bcm2835_cpufreq.c =================================================================== --- stable/10/sys/arm/broadcom/bcm2835/bcm2835_cpufreq.c (nonexistent) +++ stable/10/sys/arm/broadcom/bcm2835/bcm2835_cpufreq.c (revision 278608) @@ -0,0 +1,1818 @@ +/*- + * Copyright (C) 2013-2014 Daisuke Aoyama + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + */ + +#include +__FBSDID("$FreeBSD$"); + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include + +#include "cpufreq_if.h" +#include "mbox_if.h" + +#ifdef DEBUG +#define DPRINTF(fmt, ...) do { \ + printf("%s:%u: ", __func__, __LINE__); \ + printf(fmt, ##__VA_ARGS__); \ +} while (0) +#else +#define DPRINTF(fmt, ...) +#endif + +#define HZ2MHZ(freq) ((freq) / (1000 * 1000)) +#define MHZ2HZ(freq) ((freq) * (1000 * 1000)) +#define OFFSET2MVOLT(val) (1200 + ((val) * 25)) +#define MVOLT2OFFSET(val) (((val) - 1200) / 25) +#define RAW2K(temp) (((temp) + 273150) / 1000) +#define K2RAW(temp) (((temp) * 1000) - 273150) + +#define DEFAULT_ARM_FREQUENCY 700 +#define DEFAULT_CORE_FREQUENCY 250 +#define DEFAULT_SDRAM_FREQUENCY 400 +#define DEFAULT_LOWEST_FREQ 300 +#define TRANSITION_LATENCY 1000 +#define MIN_OVER_VOLTAGE -16 +#define MAX_OVER_VOLTAGE 6 +#define MSG_ERROR -999999999 +#define MHZSTEP 100 +#define HZSTEP (MHZ2HZ(MHZSTEP)) + +#define VC_LOCK(sc) do { \ + sema_wait(&vc_sema); \ + } while (0) +#define VC_UNLOCK(sc) do { \ + sema_post(&vc_sema); \ + } while (0) + +/* ARM->VC mailbox property semaphore */ +static struct sema vc_sema; + +static struct sysctl_ctx_list bcm2835_sysctl_ctx; + +struct bcm2835_cpufreq_softc { + device_t dev; + int arm_max_freq; + int arm_min_freq; + int core_max_freq; + int core_min_freq; + int sdram_max_freq; + int sdram_min_freq; + int max_voltage_core; + int min_voltage_core; + + /* the values written in mbox */ + int voltage_core; + int voltage_sdram; + int voltage_sdram_c; + int voltage_sdram_i; + int voltage_sdram_p; + int turbo_mode; + + /* mbox buffer (physical address) */ + bus_dma_tag_t dma_tag; + bus_dmamap_t dma_map; + bus_size_t dma_size; + void *dma_buf; + bus_addr_t dma_phys; + + /* initial hook for waiting mbox intr */ + struct intr_config_hook init_hook; +}; + +static int cpufreq_verbose = 0; +TUNABLE_INT("hw.bcm2835.cpufreq.verbose", &cpufreq_verbose); +static int cpufreq_lowest_freq = DEFAULT_LOWEST_FREQ; +TUNABLE_INT("hw.bcm2835.cpufreq.lowest_freq", &cpufreq_lowest_freq); + +#ifdef DEBUG +static void +bcm2835_dump(const void *data, int len) +{ + const uint8_t *p = (const uint8_t*)data; + int i; + + printf("dump @ %p:\n", data); + for (i = 0; i < len; i++) { + printf("%2.2x ", p[i]); + if ((i % 4) == 3) + printf(" "); + if ((i % 16) == 15) + printf("\n"); + } + printf("\n"); +} +#endif + +static int +bcm2835_mbox_call_prop(struct bcm2835_cpufreq_softc *sc) +{ + struct bcm2835_mbox_hdr *msg = (struct bcm2835_mbox_hdr *)sc->dma_buf; + struct bcm2835_mbox_tag_hdr *tag, *last; + uint8_t *up; + device_t mbox; + size_t hdr_size; + int idx; + int err; + + /* + * For multiple calls, locking is not here. The caller must have + * VC semaphore. + */ + + /* get mbox device */ + mbox = devclass_get_device(devclass_find("mbox"), 0); + if (mbox == NULL) { + device_printf(sc->dev, "can't find mbox\n"); + return (-1); + } + + /* go mailbox property */ +#ifdef PROP_DEBUG + bcm2835_dump(msg, 64); +#endif + bus_dmamap_sync(sc->dma_tag, sc->dma_map, + BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); + MBOX_WRITE(mbox, BCM2835_MBOX_CHAN_PROP, (uint32_t)sc->dma_phys); + MBOX_READ(mbox, BCM2835_MBOX_CHAN_PROP, &err); + bus_dmamap_sync(sc->dma_tag, sc->dma_map, BUS_DMASYNC_POSTREAD); +#ifdef PROP_DEBUG + bcm2835_dump(msg, 64); +#endif + + /* check response code */ + if (msg->code != BCM2835_MBOX_CODE_RESP_SUCCESS) { + device_printf(sc->dev, "mbox response error\n"); + return (-1); + } + + /* tag = first tag */ + up = (uint8_t *)msg; + hdr_size = sizeof(struct bcm2835_mbox_hdr); + tag = (struct bcm2835_mbox_tag_hdr *)(up + hdr_size); + /* last = end of buffer specified by header */ + last = (struct bcm2835_mbox_tag_hdr *)(up + msg->buf_size); + + /* loop unitl end tag (=0x0) */ + hdr_size = sizeof(struct bcm2835_mbox_tag_hdr); + for (idx = 0; tag->tag != 0; idx++) { + if ((tag->val_len & BCM2835_MBOX_TAG_VAL_LEN_RESPONSE) == 0) { + device_printf(sc->dev, "tag%d response error\n", idx); + return (-1); + } + /* clear response bit */ + tag->val_len &= ~BCM2835_MBOX_TAG_VAL_LEN_RESPONSE; + + /* get next tag */ + up = (uint8_t *)tag; + tag = (struct bcm2835_mbox_tag_hdr *)(up + hdr_size + + tag->val_buf_size); + + /* check buffer size of header */ + if (tag > last) { + device_printf(sc->dev, "mbox buffer size error\n"); + return (-1); + } + } + + return (0); +} + +static int +bcm2835_cpufreq_get_clock_rate(struct bcm2835_cpufreq_softc *sc, + uint32_t clock_id) +{ + struct msg_get_clock_rate *msg; + int rate; + int err; + + /* + * Get clock rate + * Tag: 0x00030002 + * Request: + * Length: 4 + * Value: + * u32: clock id + * Response: + * Length: 8 + * Value: + * u32: clock id + * u32: rate (in Hz) + */ + + /* using DMA buffer for VC */ + msg = (struct msg_get_clock_rate *)sc->dma_buf; + if (sizeof(*msg) > sc->dma_size) { + device_printf(sc->dev, "DMA size overflow (%zu>%lu)\n", + sizeof(*msg), sc->dma_size); + return (MSG_ERROR); + } + + /* setup single tag buffer */ + memset(msg, 0, sizeof(*msg)); + msg->hdr.buf_size = sizeof(*msg); + msg->hdr.code = BCM2835_MBOX_CODE_REQ; + msg->tag_hdr.tag = BCM2835_MBOX_TAG_GET_CLOCK_RATE; + msg->tag_hdr.val_buf_size = sizeof(msg->body); + msg->tag_hdr.val_len = sizeof(msg->body.req); + msg->body.req.clock_id = clock_id; + msg->end_tag = 0; + + /* call mailbox property */ + err = bcm2835_mbox_call_prop(sc); + if (err) { + device_printf(sc->dev, "can't get clock rate (id=%u)\n", + clock_id); + return (MSG_ERROR); + } + + /* result (Hz) */ + rate = (int)msg->body.resp.rate_hz; + DPRINTF("clock = %d(Hz)\n", rate); + return (rate); +} + +static int +bcm2835_cpufreq_get_max_clock_rate(struct bcm2835_cpufreq_softc *sc, + uint32_t clock_id) +{ + struct msg_get_max_clock_rate *msg; + int rate; + int err; + + /* + * Get max clock rate + * Tag: 0x00030004 + * Request: + * Length: 4 + * Value: + * u32: clock id + * Response: + * Length: 8 + * Value: + * u32: clock id + * u32: rate (in Hz) + */ + + /* using DMA buffer for VC */ + msg = (struct msg_get_max_clock_rate *)sc->dma_buf; + if (sizeof(*msg) > sc->dma_size) { + device_printf(sc->dev, "DMA size overflow (%zu>%lu)\n", + sizeof(*msg), sc->dma_size); + return (MSG_ERROR); + } + + /* setup single tag buffer */ + memset(msg, 0, sizeof(*msg)); + msg->hdr.buf_size = sizeof(*msg); + msg->hdr.code = BCM2835_MBOX_CODE_REQ; + msg->tag_hdr.tag = BCM2835_MBOX_TAG_GET_MAX_CLOCK_RATE; + msg->tag_hdr.val_buf_size = sizeof(msg->body); + msg->tag_hdr.val_len = sizeof(msg->body.req); + msg->body.req.clock_id = clock_id; + msg->end_tag = 0; + + /* call mailbox property */ + err = bcm2835_mbox_call_prop(sc); + if (err) { + device_printf(sc->dev, "can't get max clock rate (id=%u)\n", + clock_id); + return (MSG_ERROR); + } + + /* result (Hz) */ + rate = (int)msg->body.resp.rate_hz; + DPRINTF("clock = %d(Hz)\n", rate); + return (rate); +} + +static int +bcm2835_cpufreq_get_min_clock_rate(struct bcm2835_cpufreq_softc *sc, + uint32_t clock_id) +{ + struct msg_get_min_clock_rate *msg; + int rate; + int err; + + /* + * Get min clock rate + * Tag: 0x00030007 + * Request: + * Length: 4 + * Value: + * u32: clock id + * Response: + * Length: 8 + * Value: + * u32: clock id + * u32: rate (in Hz) + */ + + /* using DMA buffer for VC */ + msg = (struct msg_get_min_clock_rate *)sc->dma_buf; + if (sizeof(*msg) > sc->dma_size) { + device_printf(sc->dev, "DMA size overflow (%zu>%lu)\n", + sizeof(*msg), sc->dma_size); + return (MSG_ERROR); + } + + /* setup single tag buffer */ + memset(msg, 0, sizeof(*msg)); + msg->hdr.buf_size = sizeof(*msg); + msg->hdr.code = BCM2835_MBOX_CODE_REQ; + msg->tag_hdr.tag = BCM2835_MBOX_TAG_GET_MIN_CLOCK_RATE; + msg->tag_hdr.val_buf_size = sizeof(msg->body); + msg->tag_hdr.val_len = sizeof(msg->body.req); + msg->body.req.clock_id = clock_id; + msg->end_tag = 0; + + /* call mailbox property */ + err = bcm2835_mbox_call_prop(sc); + if (err) { + device_printf(sc->dev, "can't get min clock rate (id=%u)\n", + clock_id); + return (MSG_ERROR); + } + + /* result (Hz) */ + rate = (int)msg->body.resp.rate_hz; + DPRINTF("clock = %d(Hz)\n", rate); + return (rate); +} + +static int +bcm2835_cpufreq_set_clock_rate(struct bcm2835_cpufreq_softc *sc, + uint32_t clock_id, uint32_t rate_hz) +{ + struct msg_set_clock_rate *msg; + int rate; + int err; + + /* + * Set clock rate + * Tag: 0x00038002 + * Request: + * Length: 8 + * Value: + * u32: clock id + * u32: rate (in Hz) + * Response: + * Length: 8 + * Value: + * u32: clock id + * u32: rate (in Hz) + */ + + /* using DMA buffer for VC */ + msg = (struct msg_set_clock_rate *)sc->dma_buf; + if (sizeof(*msg) > sc->dma_size) { + device_printf(sc->dev, "DMA size overflow (%zu>%lu)\n", + sizeof(*msg), sc->dma_size); + return (MSG_ERROR); + } + + /* setup single tag buffer */ + memset(msg, 0, sizeof(*msg)); + msg->hdr.buf_size = sizeof(*msg); + msg->hdr.code = BCM2835_MBOX_CODE_REQ; + msg->tag_hdr.tag = BCM2835_MBOX_TAG_SET_CLOCK_RATE; + msg->tag_hdr.val_buf_size = sizeof(msg->body); + msg->tag_hdr.val_len = sizeof(msg->body.req); + msg->body.req.clock_id = clock_id; + msg->body.req.rate_hz = rate_hz; + msg->end_tag = 0; + + /* call mailbox property */ + err = bcm2835_mbox_call_prop(sc); + if (err) { + device_printf(sc->dev, "can't set clock rate (id=%u)\n", + clock_id); + return (MSG_ERROR); + } + + /* workaround for core clock */ + if (clock_id == BCM2835_MBOX_CLOCK_ID_CORE) { + /* for safety (may change voltage without changing clock) */ + DELAY(TRANSITION_LATENCY); + + /* + * XXX: the core clock is unable to change at once, + * to change certainly, write it twice now. + */ + + /* setup single tag buffer */ + memset(msg, 0, sizeof(*msg)); + msg->hdr.buf_size = sizeof(*msg); + msg->hdr.code = BCM2835_MBOX_CODE_REQ; + msg->tag_hdr.tag = BCM2835_MBOX_TAG_SET_CLOCK_RATE; + msg->tag_hdr.val_buf_size = sizeof(msg->body); + msg->tag_hdr.val_len = sizeof(msg->body.req); + msg->body.req.clock_id = clock_id; + msg->body.req.rate_hz = rate_hz; + msg->end_tag = 0; + + /* call mailbox property */ + err = bcm2835_mbox_call_prop(sc); + if (err) { + device_printf(sc->dev, + "can't set clock rate (id=%u)\n", clock_id); + return (MSG_ERROR); + } + } + + /* result (Hz) */ + rate = (int)msg->body.resp.rate_hz; + DPRINTF("clock = %d(Hz)\n", rate); + return (rate); +} + +static int +bcm2835_cpufreq_get_turbo(struct bcm2835_cpufreq_softc *sc) +{ + struct msg_get_turbo *msg; + int level; + int err; + + /* + * Get turbo + * Tag: 0x00030009 + * Request: + * Length: 4 + * Value: + * u32: id + * Response: + * Length: 8 + * Value: + * u32: id + * u32: level + */ + + /* using DMA buffer for VC */ + msg = (struct msg_get_turbo *)sc->dma_buf; + if (sizeof(*msg) > sc->dma_size) { + device_printf(sc->dev, "DMA size overflow (%zu>%lu)\n", + sizeof(*msg), sc->dma_size); + return (MSG_ERROR); + } + + /* setup single tag buffer */ + memset(msg, 0, sizeof(*msg)); + msg->hdr.buf_size = sizeof(*msg); + msg->hdr.code = BCM2835_MBOX_CODE_REQ; + msg->tag_hdr.tag = BCM2835_MBOX_TAG_GET_TURBO; + msg->tag_hdr.val_buf_size = sizeof(msg->body); + msg->tag_hdr.val_len = sizeof(msg->body.req); + msg->body.req.id = 0; + msg->end_tag = 0; + + /* call mailbox property */ + err = bcm2835_mbox_call_prop(sc); + if (err) { + device_printf(sc->dev, "can't get turbo\n"); + return (MSG_ERROR); + } + + /* result 0=non-turbo, 1=turbo */ + level = (int)msg->body.resp.level; + DPRINTF("level = %d\n", level); + return (level); +} + +static int +bcm2835_cpufreq_set_turbo(struct bcm2835_cpufreq_softc *sc, uint32_t level) +{ + struct msg_set_turbo *msg; + int value; + int err; + + /* + * Set turbo + * Tag: 0x00038009 + * Request: + * Length: 8 + * Value: + * u32: id + * u32: level + * Response: + * Length: 8 + * Value: + * u32: id + * u32: level + */ + + /* using DMA buffer for VC */ + msg = (struct msg_set_turbo *)sc->dma_buf; + if (sizeof(*msg) > sc->dma_size) { + device_printf(sc->dev, "DMA size overflow (%zu>%lu)\n", + sizeof(*msg), sc->dma_size); + return (MSG_ERROR); + } + + /* replace unknown value to OFF */ + if (level != BCM2835_MBOX_TURBO_ON && level != BCM2835_MBOX_TURBO_OFF) + level = BCM2835_MBOX_TURBO_OFF; + + /* setup single tag buffer */ + memset(msg, 0, sizeof(*msg)); + msg->hdr.buf_size = sizeof(*msg); + msg->hdr.code = BCM2835_MBOX_CODE_REQ; + msg->tag_hdr.tag = BCM2835_MBOX_TAG_SET_TURBO; + msg->tag_hdr.val_buf_size = sizeof(msg->body); + msg->tag_hdr.val_len = sizeof(msg->body.req); + msg->body.req.id = 0; + msg->body.req.level = level; + msg->end_tag = 0; + + /* call mailbox property */ + err = bcm2835_mbox_call_prop(sc); + if (err) { + device_printf(sc->dev, "can't set turbo\n"); + return (MSG_ERROR); + } + + /* result 0=non-turbo, 1=turbo */ + value = (int)msg->body.resp.level; + DPRINTF("level = %d\n", value); + return (value); +} + +static int +bcm2835_cpufreq_get_voltage(struct bcm2835_cpufreq_softc *sc, + uint32_t voltage_id) +{ + struct msg_get_voltage *msg; + int value; + int err; + + /* + * Get voltage + * Tag: 0x00030003 + * Request: + * Length: 4 + * Value: + * u32: voltage id + * Response: + * Length: 8 + * Value: + * u32: voltage id + * u32: value (offset from 1.2V in units of 0.025V) + */ + + /* using DMA buffer for VC */ + msg = (struct msg_get_voltage *)sc->dma_buf; + if (sizeof(*msg) > sc->dma_size) { + device_printf(sc->dev, "DMA size overflow (%zu>%lu)\n", + sizeof(*msg), sc->dma_size); + return (MSG_ERROR); + } + + /* setup single tag buffer */ + memset(msg, 0, sizeof(*msg)); + msg->hdr.buf_size = sizeof(*msg); + msg->hdr.code = BCM2835_MBOX_CODE_REQ; + msg->tag_hdr.tag = BCM2835_MBOX_TAG_GET_VOLTAGE; + msg->tag_hdr.val_buf_size = sizeof(msg->body); + msg->tag_hdr.val_len = sizeof(msg->body.req); + msg->body.req.voltage_id = voltage_id; + msg->end_tag = 0; + + /* call mailbox property */ + err = bcm2835_mbox_call_prop(sc); + if (err) { + device_printf(sc->dev, "can't get voltage\n"); + return (MSG_ERROR); + } + + /* result (offset from 1.2V) */ + value = (int)msg->body.resp.value; + DPRINTF("value = %d\n", value); + return (value); +} + +static int +bcm2835_cpufreq_get_max_voltage(struct bcm2835_cpufreq_softc *sc, + uint32_t voltage_id) +{ + struct msg_get_max_voltage *msg; + int value; + int err; + + /* + * Get voltage + * Tag: 0x00030005 + * Request: + * Length: 4 + * Value: + * u32: voltage id + * Response: + * Length: 8 + * Value: + * u32: voltage id + * u32: value (offset from 1.2V in units of 0.025V) + */ + + /* using DMA buffer for VC */ + msg = (struct msg_get_max_voltage *)sc->dma_buf; + if (sizeof(*msg) > sc->dma_size) { + device_printf(sc->dev, "DMA size overflow (%zu>%lu)\n", + sizeof(*msg), sc->dma_size); + return (MSG_ERROR); + } + + /* setup single tag buffer */ + memset(msg, 0, sizeof(*msg)); + msg->hdr.buf_size = sizeof(*msg); + msg->hdr.code = BCM2835_MBOX_CODE_REQ; + msg->tag_hdr.tag = BCM2835_MBOX_TAG_GET_MAX_VOLTAGE; + msg->tag_hdr.val_buf_size = sizeof(msg->body); + msg->tag_hdr.val_len = sizeof(msg->body.req); + msg->body.req.voltage_id = voltage_id; + msg->end_tag = 0; + + /* call mailbox property */ + err = bcm2835_mbox_call_prop(sc); + if (err) { + device_printf(sc->dev, "can't get max voltage\n"); + return (MSG_ERROR); + } + + /* result (offset from 1.2V) */ + value = (int)msg->body.resp.value; + DPRINTF("value = %d\n", value); + return (value); +} +static int +bcm2835_cpufreq_get_min_voltage(struct bcm2835_cpufreq_softc *sc, + uint32_t voltage_id) +{ + struct msg_get_min_voltage *msg; + int value; + int err; + + /* + * Get voltage + * Tag: 0x00030008 + * Request: + * Length: 4 + * Value: + * u32: voltage id + * Response: + * Length: 8 + * Value: + * u32: voltage id + * u32: value (offset from 1.2V in units of 0.025V) + */ + + /* using DMA buffer for VC */ + msg = (struct msg_get_min_voltage *)sc->dma_buf; + if (sizeof(*msg) > sc->dma_size) { + device_printf(sc->dev, "DMA size overflow (%zu>%lu)\n", + sizeof(*msg), sc->dma_size); + return (MSG_ERROR); + } + + /* setup single tag buffer */ + memset(msg, 0, sizeof(*msg)); + msg->hdr.buf_size = sizeof(*msg); + msg->hdr.code = BCM2835_MBOX_CODE_REQ; + msg->tag_hdr.tag = BCM2835_MBOX_TAG_GET_MIN_VOLTAGE; + msg->tag_hdr.val_buf_size = sizeof(msg->body); + msg->tag_hdr.val_len = sizeof(msg->body.req); + msg->body.req.voltage_id = voltage_id; + msg->end_tag = 0; + + /* call mailbox property */ + err = bcm2835_mbox_call_prop(sc); + if (err) { + device_printf(sc->dev, "can't get min voltage\n"); + return (MSG_ERROR); + } + + /* result (offset from 1.2V) */ + value = (int)msg->body.resp.value; + DPRINTF("value = %d\n", value); + return (value); +} + +static int +bcm2835_cpufreq_set_voltage(struct bcm2835_cpufreq_softc *sc, + uint32_t voltage_id, int32_t value) +{ + struct msg_set_voltage *msg; + int err; + + /* + * Set voltage + * Tag: 0x00038003 + * Request: + * Length: 4 + * Value: + * u32: voltage id + * u32: value (offset from 1.2V in units of 0.025V) + * Response: + * Length: 8 + * Value: + * u32: voltage id + * u32: value (offset from 1.2V in units of 0.025V) + */ + + /* + * over_voltage: + * 0 (1.2 V). Values above 6 are only allowed when force_turbo or + * current_limit_override are specified (which set the warranty bit). + */ + if (value > MAX_OVER_VOLTAGE || value < MIN_OVER_VOLTAGE) { + /* currently not supported */ + device_printf(sc->dev, "not supported voltage: %d\n", value); + return (MSG_ERROR); + } + + /* using DMA buffer for VC */ + msg = (struct msg_set_voltage *)sc->dma_buf; + if (sizeof(*msg) > sc->dma_size) { + device_printf(sc->dev, "DMA size overflow (%zu>%lu)\n", + sizeof(*msg), sc->dma_size); + return (MSG_ERROR); + } + + /* setup single tag buffer */ + memset(msg, 0, sizeof(*msg)); + msg->hdr.buf_size = sizeof(*msg); + msg->hdr.code = BCM2835_MBOX_CODE_REQ; + msg->tag_hdr.tag = BCM2835_MBOX_TAG_SET_VOLTAGE; + msg->tag_hdr.val_buf_size = sizeof(msg->body); + msg->tag_hdr.val_len = sizeof(msg->body.req); + msg->body.req.voltage_id = voltage_id; + msg->body.req.value = (uint32_t)value; + msg->end_tag = 0; + + /* call mailbox property */ + err = bcm2835_mbox_call_prop(sc); + if (err) { + device_printf(sc->dev, "can't set voltage\n"); + return (MSG_ERROR); + } + + /* result (offset from 1.2V) */ + value = (int)msg->body.resp.value; + DPRINTF("value = %d\n", value); + return (value); +} + +static int +bcm2835_cpufreq_get_temperature(struct bcm2835_cpufreq_softc *sc) +{ + struct msg_get_temperature *msg; + int value; + int err; + + /* + * Get temperature + * Tag: 0x00030006 + * Request: + * Length: 4 + * Value: + * u32: temperature id + * Response: + * Length: 8 + * Value: + * u32: temperature id + * u32: value + */ + + /* using DMA buffer for VC */ + msg = (struct msg_get_temperature *)sc->dma_buf; + if (sizeof(*msg) > sc->dma_size) { + device_printf(sc->dev, "DMA size overflow (%zu>%lu)\n", + sizeof(*msg), sc->dma_size); + return (MSG_ERROR); + } + + /* setup single tag buffer */ + memset(msg, 0, sizeof(*msg)); + msg->hdr.buf_size = sizeof(*msg); + msg->hdr.code = BCM2835_MBOX_CODE_REQ; + msg->tag_hdr.tag = BCM2835_MBOX_TAG_GET_TEMPERATURE; + msg->tag_hdr.val_buf_size = sizeof(msg->body); + msg->tag_hdr.val_len = sizeof(msg->body.req); + msg->body.req.temperature_id = 0; + msg->end_tag = 0; + + /* call mailbox property */ + err = bcm2835_mbox_call_prop(sc); + if (err) { + device_printf(sc->dev, "can't get temperature\n"); + return (MSG_ERROR); + } + + /* result (temperature of degree C) */ + value = (int)msg->body.resp.value; + DPRINTF("value = %d\n", value); + return (value); +} + + + +static int +sysctl_bcm2835_cpufreq_arm_freq(SYSCTL_HANDLER_ARGS) +{ + struct bcm2835_cpufreq_softc *sc = arg1; + int val; + int err; + + /* get realtime value */ + VC_LOCK(sc); + val = bcm2835_cpufreq_get_clock_rate(sc, BCM2835_MBOX_CLOCK_ID_ARM); + VC_UNLOCK(sc); + if (val == MSG_ERROR) + return (EIO); + + err = sysctl_handle_int(oidp, &val, 0, req); + if (err || !req->newptr) /* error || read request */ + return (err); + + /* write request */ + VC_LOCK(sc); + err = bcm2835_cpufreq_set_clock_rate(sc, BCM2835_MBOX_CLOCK_ID_ARM, + val); + VC_UNLOCK(sc); + if (err == MSG_ERROR) { + device_printf(sc->dev, "set clock arm_freq error\n"); + return (EIO); + } + DELAY(TRANSITION_LATENCY); + + return (0); +} + +static int +sysctl_bcm2835_cpufreq_core_freq(SYSCTL_HANDLER_ARGS) +{ + struct bcm2835_cpufreq_softc *sc = arg1; + int val; + int err; + + /* get realtime value */ + VC_LOCK(sc); + val = bcm2835_cpufreq_get_clock_rate(sc, BCM2835_MBOX_CLOCK_ID_CORE); + VC_UNLOCK(sc); + if (val == MSG_ERROR) + return (EIO); + + err = sysctl_handle_int(oidp, &val, 0, req); + if (err || !req->newptr) /* error || read request */ + return (err); + + /* write request */ + VC_LOCK(sc); + err = bcm2835_cpufreq_set_clock_rate(sc, BCM2835_MBOX_CLOCK_ID_CORE, + val); + if (err == MSG_ERROR) { + VC_UNLOCK(sc); + device_printf(sc->dev, "set clock core_freq error\n"); + return (EIO); + } + VC_UNLOCK(sc); + DELAY(TRANSITION_LATENCY); + + return (0); +} + +static int +sysctl_bcm2835_cpufreq_sdram_freq(SYSCTL_HANDLER_ARGS) +{ + struct bcm2835_cpufreq_softc *sc = arg1; + int val; + int err; + + /* get realtime value */ + VC_LOCK(sc); + val = bcm2835_cpufreq_get_clock_rate(sc, BCM2835_MBOX_CLOCK_ID_SDRAM); + VC_UNLOCK(sc); + if (val == MSG_ERROR) + return (EIO); + + err = sysctl_handle_int(oidp, &val, 0, req); + if (err || !req->newptr) /* error || read request */ + return (err); + + /* write request */ + VC_LOCK(sc); + err = bcm2835_cpufreq_set_clock_rate(sc, BCM2835_MBOX_CLOCK_ID_SDRAM, + val); + VC_UNLOCK(sc); + if (err == MSG_ERROR) { + device_printf(sc->dev, "set clock sdram_freq error\n"); + return (EIO); + } + DELAY(TRANSITION_LATENCY); + + return (0); +} + +static int +sysctl_bcm2835_cpufreq_turbo(SYSCTL_HANDLER_ARGS) +{ + struct bcm2835_cpufreq_softc *sc = arg1; + int val; + int err; + + /* get realtime value */ + VC_LOCK(sc); + val = bcm2835_cpufreq_get_turbo(sc); + VC_UNLOCK(sc); + if (val == MSG_ERROR) + return (EIO); + + err = sysctl_handle_int(oidp, &val, 0, req); + if (err || !req->newptr) /* error || read request */ + return (err); + + /* write request */ + if (val > 0) + sc->turbo_mode = BCM2835_MBOX_TURBO_ON; + else + sc->turbo_mode = BCM2835_MBOX_TURBO_OFF; + + VC_LOCK(sc); + err = bcm2835_cpufreq_set_turbo(sc, sc->turbo_mode); + VC_UNLOCK(sc); + if (err == MSG_ERROR) { + device_printf(sc->dev, "set turbo error\n"); + return (EIO); + } + DELAY(TRANSITION_LATENCY); + + return (0); +} + +static int +sysctl_bcm2835_cpufreq_voltage_core(SYSCTL_HANDLER_ARGS) +{ + struct bcm2835_cpufreq_softc *sc = arg1; + int val; + int err; + + /* get realtime value */ + VC_LOCK(sc); + val = bcm2835_cpufreq_get_voltage(sc, BCM2835_MBOX_VOLTAGE_ID_CORE); + VC_UNLOCK(sc); + if (val == MSG_ERROR) + return (EIO); + + err = sysctl_handle_int(oidp, &val, 0, req); + if (err || !req->newptr) /* error || read request */ + return (err); + + /* write request */ + if (val > MAX_OVER_VOLTAGE || val < MIN_OVER_VOLTAGE) + return (EINVAL); + sc->voltage_core = val; + + VC_LOCK(sc); + err = bcm2835_cpufreq_set_voltage(sc, BCM2835_MBOX_VOLTAGE_ID_CORE, + sc->voltage_core); + VC_UNLOCK(sc); + if (err == MSG_ERROR) { + device_printf(sc->dev, "set voltage core error\n"); + return (EIO); + } + DELAY(TRANSITION_LATENCY); + + return (0); +} + +static int +sysctl_bcm2835_cpufreq_voltage_sdram_c(SYSCTL_HANDLER_ARGS) +{ + struct bcm2835_cpufreq_softc *sc = arg1; + int val; + int err; + + /* get realtime value */ + VC_LOCK(sc); + val = bcm2835_cpufreq_get_voltage(sc, BCM2835_MBOX_VOLTAGE_ID_SDRAM_C); + VC_UNLOCK(sc); + if (val == MSG_ERROR) + return (EIO); + + err = sysctl_handle_int(oidp, &val, 0, req); + if (err || !req->newptr) /* error || read request */ + return (err); + + /* write request */ + if (val > MAX_OVER_VOLTAGE || val < MIN_OVER_VOLTAGE) + return (EINVAL); + sc->voltage_sdram_c = val; + + VC_LOCK(sc); + err = bcm2835_cpufreq_set_voltage(sc, BCM2835_MBOX_VOLTAGE_ID_SDRAM_C, + sc->voltage_sdram_c); + VC_UNLOCK(sc); + if (err == MSG_ERROR) { + device_printf(sc->dev, "set voltage sdram_c error\n"); + return (EIO); + } + DELAY(TRANSITION_LATENCY); + + return (0); +} + +static int +sysctl_bcm2835_cpufreq_voltage_sdram_i(SYSCTL_HANDLER_ARGS) +{ + struct bcm2835_cpufreq_softc *sc = arg1; + int val; + int err; + + /* get realtime value */ + VC_LOCK(sc); + val = bcm2835_cpufreq_get_voltage(sc, BCM2835_MBOX_VOLTAGE_ID_SDRAM_I); + VC_UNLOCK(sc); + if (val == MSG_ERROR) + return (EIO); + + err = sysctl_handle_int(oidp, &val, 0, req); + if (err || !req->newptr) /* error || read request */ + return (err); + + /* write request */ + if (val > MAX_OVER_VOLTAGE || val < MIN_OVER_VOLTAGE) + return (EINVAL); + sc->voltage_sdram_i = val; + + VC_LOCK(sc); + err = bcm2835_cpufreq_set_voltage(sc, BCM2835_MBOX_VOLTAGE_ID_SDRAM_I, + sc->voltage_sdram_i); + VC_UNLOCK(sc); + if (err == MSG_ERROR) { + device_printf(sc->dev, "set voltage sdram_i error\n"); + return (EIO); + } + DELAY(TRANSITION_LATENCY); + + return (0); +} + +static int +sysctl_bcm2835_cpufreq_voltage_sdram_p(SYSCTL_HANDLER_ARGS) +{ + struct bcm2835_cpufreq_softc *sc = arg1; + int val; + int err; + + /* get realtime value */ + VC_LOCK(sc); + val = bcm2835_cpufreq_get_voltage(sc, BCM2835_MBOX_VOLTAGE_ID_SDRAM_P); + VC_UNLOCK(sc); + if (val == MSG_ERROR) + return (EIO); + + err = sysctl_handle_int(oidp, &val, 0, req); + if (err || !req->newptr) /* error || read request */ + return (err); + + /* write request */ + if (val > MAX_OVER_VOLTAGE || val < MIN_OVER_VOLTAGE) + return (EINVAL); + sc->voltage_sdram_p = val; + + VC_LOCK(sc); + err = bcm2835_cpufreq_set_voltage(sc, BCM2835_MBOX_VOLTAGE_ID_SDRAM_P, + sc->voltage_sdram_p); + VC_UNLOCK(sc); + if (err == MSG_ERROR) { + device_printf(sc->dev, "set voltage sdram_p error\n"); + return (EIO); + } + DELAY(TRANSITION_LATENCY); + + return (0); +} + +static int +sysctl_bcm2835_cpufreq_voltage_sdram(SYSCTL_HANDLER_ARGS) +{ + struct bcm2835_cpufreq_softc *sc = arg1; + int val; + int err; + + /* multiple write only */ + if (!req->newptr) + return (EINVAL); + val = 0; + err = sysctl_handle_int(oidp, &val, 0, req); + if (err) + return (err); + + /* write request */ + if (val > MAX_OVER_VOLTAGE || val < MIN_OVER_VOLTAGE) + return (EINVAL); + sc->voltage_sdram = val; + + VC_LOCK(sc); + err = bcm2835_cpufreq_set_voltage(sc, BCM2835_MBOX_VOLTAGE_ID_SDRAM_C, + val); + if (err == MSG_ERROR) { + VC_UNLOCK(sc); + device_printf(sc->dev, "set voltage sdram_c error\n"); + return (EIO); + } + err = bcm2835_cpufreq_set_voltage(sc, BCM2835_MBOX_VOLTAGE_ID_SDRAM_I, + val); + if (err == MSG_ERROR) { + VC_UNLOCK(sc); + device_printf(sc->dev, "set voltage sdram_i error\n"); + return (EIO); + } + err = bcm2835_cpufreq_set_voltage(sc, BCM2835_MBOX_VOLTAGE_ID_SDRAM_P, + val); + if (err == MSG_ERROR) { + VC_UNLOCK(sc); + device_printf(sc->dev, "set voltage sdram_p error\n"); + return (EIO); + } + VC_UNLOCK(sc); + DELAY(TRANSITION_LATENCY); + + return (0); +} + +static int +sysctl_bcm2835_cpufreq_temperature(SYSCTL_HANDLER_ARGS) +{ + struct bcm2835_cpufreq_softc *sc = arg1; + int val; + int err; + + /* get realtime value */ + VC_LOCK(sc); + val = bcm2835_cpufreq_get_temperature(sc); + VC_UNLOCK(sc); + if (val == MSG_ERROR) + return (EIO); + + err = sysctl_handle_int(oidp, &val, 0, req); + if (err || !req->newptr) /* error || read request */ + return (err); + + /* write request */ + return (EINVAL); +} + +static int +sysctl_bcm2835_devcpu_temperature(SYSCTL_HANDLER_ARGS) +{ + struct bcm2835_cpufreq_softc *sc = arg1; + int val; + int err; + + /* get realtime value */ + VC_LOCK(sc); + val = bcm2835_cpufreq_get_temperature(sc); + VC_UNLOCK(sc); + if (val == MSG_ERROR) + return (EIO); + + /* 1/1000 celsius (raw) to 1/10 kelvin */ + val = RAW2K(val) * 10; + + err = sysctl_handle_int(oidp, &val, 0, req); + if (err || !req->newptr) /* error || read request */ + return (err); + + /* write request */ + return (EINVAL); +} + + +static void +bcm2835_cpufreq_init(void *arg) +{ + struct bcm2835_cpufreq_softc *sc = arg; + struct sysctl_ctx_list *ctx; + device_t cpu; + int arm_freq, core_freq, sdram_freq; + int arm_max_freq, arm_min_freq, core_max_freq, core_min_freq; + int sdram_max_freq, sdram_min_freq; + int voltage_core, voltage_sdram_c, voltage_sdram_i, voltage_sdram_p; + int max_voltage_core, min_voltage_core; + int max_voltage_sdram_c, min_voltage_sdram_c; + int max_voltage_sdram_i, min_voltage_sdram_i; + int max_voltage_sdram_p, min_voltage_sdram_p; + int turbo, temperature; + + VC_LOCK(sc); + + /* current clock */ + arm_freq = bcm2835_cpufreq_get_clock_rate(sc, + BCM2835_MBOX_CLOCK_ID_ARM); + core_freq = bcm2835_cpufreq_get_clock_rate(sc, + BCM2835_MBOX_CLOCK_ID_CORE); + sdram_freq = bcm2835_cpufreq_get_clock_rate(sc, + BCM2835_MBOX_CLOCK_ID_SDRAM); + + /* max/min clock */ + arm_max_freq = bcm2835_cpufreq_get_max_clock_rate(sc, + BCM2835_MBOX_CLOCK_ID_ARM); + arm_min_freq = bcm2835_cpufreq_get_min_clock_rate(sc, + BCM2835_MBOX_CLOCK_ID_ARM); + core_max_freq = bcm2835_cpufreq_get_max_clock_rate(sc, + BCM2835_MBOX_CLOCK_ID_CORE); + core_min_freq = bcm2835_cpufreq_get_min_clock_rate(sc, + BCM2835_MBOX_CLOCK_ID_CORE); + sdram_max_freq = bcm2835_cpufreq_get_max_clock_rate(sc, + BCM2835_MBOX_CLOCK_ID_SDRAM); + sdram_min_freq = bcm2835_cpufreq_get_min_clock_rate(sc, + BCM2835_MBOX_CLOCK_ID_SDRAM); + + /* turbo mode */ + turbo = bcm2835_cpufreq_get_turbo(sc); + if (turbo > 0) + sc->turbo_mode = BCM2835_MBOX_TURBO_ON; + else + sc->turbo_mode = BCM2835_MBOX_TURBO_OFF; + + /* voltage */ + voltage_core = bcm2835_cpufreq_get_voltage(sc, + BCM2835_MBOX_VOLTAGE_ID_CORE); + voltage_sdram_c = bcm2835_cpufreq_get_voltage(sc, + BCM2835_MBOX_VOLTAGE_ID_SDRAM_C); + voltage_sdram_i = bcm2835_cpufreq_get_voltage(sc, + BCM2835_MBOX_VOLTAGE_ID_SDRAM_I); + voltage_sdram_p = bcm2835_cpufreq_get_voltage(sc, + BCM2835_MBOX_VOLTAGE_ID_SDRAM_P); + + /* current values (offset from 1.2V) */ + sc->voltage_core = voltage_core; + sc->voltage_sdram = voltage_sdram_c; + sc->voltage_sdram_c = voltage_sdram_c; + sc->voltage_sdram_i = voltage_sdram_i; + sc->voltage_sdram_p = voltage_sdram_p; + + /* max/min voltage */ + max_voltage_core = bcm2835_cpufreq_get_max_voltage(sc, + BCM2835_MBOX_VOLTAGE_ID_CORE); + min_voltage_core = bcm2835_cpufreq_get_min_voltage(sc, + BCM2835_MBOX_VOLTAGE_ID_CORE); + max_voltage_sdram_c = bcm2835_cpufreq_get_max_voltage(sc, + BCM2835_MBOX_VOLTAGE_ID_SDRAM_C); + max_voltage_sdram_i = bcm2835_cpufreq_get_max_voltage(sc, + BCM2835_MBOX_VOLTAGE_ID_SDRAM_I); + max_voltage_sdram_p = bcm2835_cpufreq_get_max_voltage(sc, + BCM2835_MBOX_VOLTAGE_ID_SDRAM_P); + min_voltage_sdram_c = bcm2835_cpufreq_get_min_voltage(sc, + BCM2835_MBOX_VOLTAGE_ID_SDRAM_C); + min_voltage_sdram_i = bcm2835_cpufreq_get_min_voltage(sc, + BCM2835_MBOX_VOLTAGE_ID_SDRAM_I); + min_voltage_sdram_p = bcm2835_cpufreq_get_min_voltage(sc, + BCM2835_MBOX_VOLTAGE_ID_SDRAM_P); + + /* temperature */ + temperature = bcm2835_cpufreq_get_temperature(sc); + + /* show result */ + if (cpufreq_verbose || bootverbose) { + device_printf(sc->dev, "Boot settings:\n"); + device_printf(sc->dev, + "current ARM %dMHz, Core %dMHz, SDRAM %dMHz, Turbo %s\n", + HZ2MHZ(arm_freq), HZ2MHZ(core_freq), HZ2MHZ(sdram_freq), + (sc->turbo_mode == BCM2835_MBOX_TURBO_ON) ? "ON" : "OFF"); + + device_printf(sc->dev, + "max/min ARM %d/%dMHz, Core %d/%dMHz, SDRAM %d/%dMHz\n", + HZ2MHZ(arm_max_freq), HZ2MHZ(arm_min_freq), + HZ2MHZ(core_max_freq), HZ2MHZ(core_min_freq), + HZ2MHZ(sdram_max_freq), HZ2MHZ(sdram_min_freq)); + + device_printf(sc->dev, + "current Core %dmV, SDRAM_C %dmV, SDRAM_I %dmV, " + "SDRAM_P %dmV\n", + OFFSET2MVOLT(voltage_core), OFFSET2MVOLT(voltage_sdram_c), + OFFSET2MVOLT(voltage_sdram_i), + OFFSET2MVOLT(voltage_sdram_p)); + + device_printf(sc->dev, + "max/min Core %d/%dmV, SDRAM_C %d/%dmV, SDRAM_I %d/%dmV, " + "SDRAM_P %d/%dmV\n", + OFFSET2MVOLT(max_voltage_core), + OFFSET2MVOLT(min_voltage_core), + OFFSET2MVOLT(max_voltage_sdram_c), + OFFSET2MVOLT(min_voltage_sdram_c), + OFFSET2MVOLT(max_voltage_sdram_i), + OFFSET2MVOLT(min_voltage_sdram_i), + OFFSET2MVOLT(max_voltage_sdram_p), + OFFSET2MVOLT(min_voltage_sdram_p)); + + device_printf(sc->dev, + "Temperature %d.%dC\n", (temperature / 1000), + (temperature % 1000) / 100); + } else { /* !cpufreq_verbose && !bootverbose */ + device_printf(sc->dev, + "ARM %dMHz, Core %dMHz, SDRAM %dMHz, Turbo %s\n", + HZ2MHZ(arm_freq), HZ2MHZ(core_freq), HZ2MHZ(sdram_freq), + (sc->turbo_mode == BCM2835_MBOX_TURBO_ON) ? "ON" : "OFF"); + } + + /* keep in softc (MHz/mV) */ + sc->arm_max_freq = HZ2MHZ(arm_max_freq); + sc->arm_min_freq = HZ2MHZ(arm_min_freq); + sc->core_max_freq = HZ2MHZ(core_max_freq); + sc->core_min_freq = HZ2MHZ(core_min_freq); + sc->sdram_max_freq = HZ2MHZ(sdram_max_freq); + sc->sdram_min_freq = HZ2MHZ(sdram_min_freq); + sc->max_voltage_core = OFFSET2MVOLT(max_voltage_core); + sc->min_voltage_core = OFFSET2MVOLT(min_voltage_core); + + /* if turbo is on, set to max values */ + if (sc->turbo_mode == BCM2835_MBOX_TURBO_ON) { + bcm2835_cpufreq_set_clock_rate(sc, BCM2835_MBOX_CLOCK_ID_ARM, + arm_max_freq); + DELAY(TRANSITION_LATENCY); + bcm2835_cpufreq_set_clock_rate(sc, BCM2835_MBOX_CLOCK_ID_CORE, + core_max_freq); + DELAY(TRANSITION_LATENCY); + bcm2835_cpufreq_set_clock_rate(sc, + BCM2835_MBOX_CLOCK_ID_SDRAM, sdram_max_freq); + DELAY(TRANSITION_LATENCY); + } else { + bcm2835_cpufreq_set_clock_rate(sc, BCM2835_MBOX_CLOCK_ID_ARM, + arm_min_freq); + DELAY(TRANSITION_LATENCY); + bcm2835_cpufreq_set_clock_rate(sc, BCM2835_MBOX_CLOCK_ID_CORE, + core_min_freq); + DELAY(TRANSITION_LATENCY); + bcm2835_cpufreq_set_clock_rate(sc, + BCM2835_MBOX_CLOCK_ID_SDRAM, sdram_min_freq); + DELAY(TRANSITION_LATENCY); + } + + VC_UNLOCK(sc); + + /* add human readable temperature to dev.cpu node */ + cpu = device_get_parent(sc->dev); + if (cpu != NULL) { + ctx = device_get_sysctl_ctx(cpu); + SYSCTL_ADD_PROC(ctx, + SYSCTL_CHILDREN(device_get_sysctl_tree(cpu)), OID_AUTO, + "temperature", CTLTYPE_INT | CTLFLAG_RD, sc, 0, + sysctl_bcm2835_devcpu_temperature, "IK", + "Current SoC temperature"); + } + + /* release this hook (continue boot) */ + config_intrhook_disestablish(&sc->init_hook); +} + +static void +bcm2835_cpufreq_identify(driver_t *driver, device_t parent) +{ + + DPRINTF("driver=%p, parent=%p\n", driver, parent); + if (device_find_child(parent, "bcm2835_cpufreq", -1) != NULL) + return; + if (BUS_ADD_CHILD(parent, 0, "bcm2835_cpufreq", -1) == NULL) + device_printf(parent, "add child failed\n"); +} + +static int +bcm2835_cpufreq_probe(device_t dev) +{ + + device_set_desc(dev, "CPU Frequency Control"); + return (0); +} + +static void +bcm2835_cpufreq_cb(void *arg, bus_dma_segment_t *segs, int nseg, int err) +{ + bus_addr_t *addr; + + if (err) + return; + addr = (bus_addr_t *)arg; + *addr = PHYS_TO_VCBUS(segs[0].ds_addr); +} + +static int +bcm2835_cpufreq_attach(device_t dev) +{ + struct bcm2835_cpufreq_softc *sc; + struct sysctl_oid *oid; + int err; + + /* set self dev */ + sc = device_get_softc(dev); + sc->dev = dev; + + /* initial values */ + sc->arm_max_freq = -1; + sc->arm_min_freq = -1; + sc->core_max_freq = -1; + sc->core_min_freq = -1; + sc->sdram_max_freq = -1; + sc->sdram_min_freq = -1; + sc->max_voltage_core = 0; + sc->min_voltage_core = 0; + + /* create VC mbox buffer */ + sc->dma_size = PAGE_SIZE; + err = bus_dma_tag_create( + bus_get_dma_tag(sc->dev), + PAGE_SIZE, 0, /* alignment, boundary */ + BUS_SPACE_MAXADDR_32BIT, /* lowaddr */ + BUS_SPACE_MAXADDR, /* highaddr */ + NULL, NULL, /* filter, filterarg */ + sc->dma_size, 1, /* maxsize, nsegments */ + sc->dma_size, 0, /* maxsegsize, flags */ + NULL, NULL, /* lockfunc, lockarg */ + &sc->dma_tag); + if (err) { + device_printf(dev, "can't create DMA tag\n"); + return (ENXIO); + } + + err = bus_dmamem_alloc(sc->dma_tag, (void **)&sc->dma_buf, 0, + &sc->dma_map); + if (err) { + bus_dma_tag_destroy(sc->dma_tag); + device_printf(dev, "can't allocate dmamem\n"); + return (ENXIO); + } + + err = bus_dmamap_load(sc->dma_tag, sc->dma_map, sc->dma_buf, + sc->dma_size, bcm2835_cpufreq_cb, &sc->dma_phys, 0); + if (err) { + bus_dmamem_free(sc->dma_tag, sc->dma_buf, sc->dma_map); + bus_dma_tag_destroy(sc->dma_tag); + device_printf(dev, "can't load DMA map\n"); + return (ENXIO); + } + /* OK, ready to use VC buffer */ + + /* setup sysctl at first device */ + if (device_get_unit(dev) == 0) { + sysctl_ctx_init(&bcm2835_sysctl_ctx); + /* create node for hw.cpufreq */ + oid = SYSCTL_ADD_NODE(&bcm2835_sysctl_ctx, + SYSCTL_STATIC_CHILDREN(_hw), OID_AUTO, "cpufreq", + CTLFLAG_RD, NULL, ""); + + /* Frequency (Hz) */ + SYSCTL_ADD_PROC(&bcm2835_sysctl_ctx, SYSCTL_CHILDREN(oid), + OID_AUTO, "arm_freq", CTLTYPE_INT | CTLFLAG_RW, sc, 0, + sysctl_bcm2835_cpufreq_arm_freq, "IU", + "ARM frequency (Hz)"); + SYSCTL_ADD_PROC(&bcm2835_sysctl_ctx, SYSCTL_CHILDREN(oid), + OID_AUTO, "core_freq", CTLTYPE_INT | CTLFLAG_RW, sc, 0, + sysctl_bcm2835_cpufreq_core_freq, "IU", + "Core frequency (Hz)"); + SYSCTL_ADD_PROC(&bcm2835_sysctl_ctx, SYSCTL_CHILDREN(oid), + OID_AUTO, "sdram_freq", CTLTYPE_INT | CTLFLAG_RW, sc, 0, + sysctl_bcm2835_cpufreq_sdram_freq, "IU", + "SDRAM frequency (Hz)"); + + /* Turbo state */ + SYSCTL_ADD_PROC(&bcm2835_sysctl_ctx, SYSCTL_CHILDREN(oid), + OID_AUTO, "turbo", CTLTYPE_INT | CTLFLAG_RW, sc, 0, + sysctl_bcm2835_cpufreq_turbo, "IU", + "Disables dynamic clocking"); + + /* Voltage (offset from 1.2V in units of 0.025V) */ + SYSCTL_ADD_PROC(&bcm2835_sysctl_ctx, SYSCTL_CHILDREN(oid), + OID_AUTO, "voltage_core", CTLTYPE_INT | CTLFLAG_RW, sc, 0, + sysctl_bcm2835_cpufreq_voltage_core, "I", + "ARM/GPU core voltage" + "(offset from 1.2V in units of 0.025V)"); + SYSCTL_ADD_PROC(&bcm2835_sysctl_ctx, SYSCTL_CHILDREN(oid), + OID_AUTO, "voltage_sdram", CTLTYPE_INT | CTLFLAG_WR, sc, + 0, sysctl_bcm2835_cpufreq_voltage_sdram, "I", + "SDRAM voltage (offset from 1.2V in units of 0.025V)"); + + /* Voltage individual SDRAM */ + SYSCTL_ADD_PROC(&bcm2835_sysctl_ctx, SYSCTL_CHILDREN(oid), + OID_AUTO, "voltage_sdram_c", CTLTYPE_INT | CTLFLAG_RW, sc, + 0, sysctl_bcm2835_cpufreq_voltage_sdram_c, "I", + "SDRAM controller voltage" + "(offset from 1.2V in units of 0.025V)"); + SYSCTL_ADD_PROC(&bcm2835_sysctl_ctx, SYSCTL_CHILDREN(oid), + OID_AUTO, "voltage_sdram_i", CTLTYPE_INT | CTLFLAG_RW, sc, + 0, sysctl_bcm2835_cpufreq_voltage_sdram_i, "I", + "SDRAM I/O voltage (offset from 1.2V in units of 0.025V)"); + SYSCTL_ADD_PROC(&bcm2835_sysctl_ctx, SYSCTL_CHILDREN(oid), + OID_AUTO, "voltage_sdram_p", CTLTYPE_INT | CTLFLAG_RW, sc, + 0, sysctl_bcm2835_cpufreq_voltage_sdram_p, "I", + "SDRAM phy voltage (offset from 1.2V in units of 0.025V)"); + + /* Temperature */ + SYSCTL_ADD_PROC(&bcm2835_sysctl_ctx, SYSCTL_CHILDREN(oid), + OID_AUTO, "temperature", CTLTYPE_INT | CTLFLAG_RD, sc, 0, + sysctl_bcm2835_cpufreq_temperature, "I", + "SoC temperature (thousandths of a degree C)"); + } + + /* ARM->VC lock */ + sema_init(&vc_sema, 1, "vcsema"); + + /* register callback for using mbox when interrupts are enabled */ + sc->init_hook.ich_func = bcm2835_cpufreq_init; + sc->init_hook.ich_arg = sc; + + if (config_intrhook_establish(&sc->init_hook) != 0) { + bus_dmamap_unload(sc->dma_tag, sc->dma_map); + bus_dmamem_free(sc->dma_tag, sc->dma_buf, sc->dma_map); + bus_dma_tag_destroy(sc->dma_tag); + device_printf(dev, "config_intrhook_establish failed\n"); + return (ENOMEM); + } + + /* this device is controlled by cpufreq(4) */ + cpufreq_register(dev); + + return (0); +} + +static int +bcm2835_cpufreq_detach(device_t dev) +{ + struct bcm2835_cpufreq_softc *sc; + + sc = device_get_softc(dev); + + sema_destroy(&vc_sema); + + if (sc->dma_phys != 0) + bus_dmamap_unload(sc->dma_tag, sc->dma_map); + if (sc->dma_buf != NULL) + bus_dmamem_free(sc->dma_tag, sc->dma_buf, sc->dma_map); + if (sc->dma_tag != NULL) + bus_dma_tag_destroy(sc->dma_tag); + + return (cpufreq_unregister(dev)); +} + +static int +bcm2835_cpufreq_set(device_t dev, const struct cf_setting *cf) +{ + struct bcm2835_cpufreq_softc *sc; + uint32_t rate_hz, rem; + int cur_freq, resp_freq, arm_freq, min_freq, core_freq; + + if (cf == NULL || cf->freq < 0) + return (EINVAL); + + sc = device_get_softc(dev); + + /* setting clock (Hz) */ + rate_hz = (uint32_t)MHZ2HZ(cf->freq); + rem = rate_hz % HZSTEP; + rate_hz -= rem; + if (rate_hz == 0) + return (EINVAL); + + /* adjust min freq */ + min_freq = sc->arm_min_freq; + if (sc->turbo_mode != BCM2835_MBOX_TURBO_ON) + if (min_freq > cpufreq_lowest_freq) + min_freq = cpufreq_lowest_freq; + + if (rate_hz < MHZ2HZ(min_freq) || rate_hz > MHZ2HZ(sc->arm_max_freq)) + return (EINVAL); + + /* set new value and verify it */ + VC_LOCK(sc); + cur_freq = bcm2835_cpufreq_get_clock_rate(sc, + BCM2835_MBOX_CLOCK_ID_ARM); + resp_freq = bcm2835_cpufreq_set_clock_rate(sc, + BCM2835_MBOX_CLOCK_ID_ARM, rate_hz); + DELAY(TRANSITION_LATENCY); + arm_freq = bcm2835_cpufreq_get_clock_rate(sc, + BCM2835_MBOX_CLOCK_ID_ARM); + + /* + * if non-turbo and lower than or equal min_freq, + * clock down core and sdram to default first. + */ + if (sc->turbo_mode != BCM2835_MBOX_TURBO_ON) { + core_freq = bcm2835_cpufreq_get_clock_rate(sc, + BCM2835_MBOX_CLOCK_ID_CORE); + if (rate_hz > MHZ2HZ(sc->arm_min_freq)) { + bcm2835_cpufreq_set_clock_rate(sc, + BCM2835_MBOX_CLOCK_ID_CORE, + MHZ2HZ(sc->core_max_freq)); + DELAY(TRANSITION_LATENCY); + bcm2835_cpufreq_set_clock_rate(sc, + BCM2835_MBOX_CLOCK_ID_SDRAM, + MHZ2HZ(sc->sdram_max_freq)); + DELAY(TRANSITION_LATENCY); + } else { + if (sc->core_min_freq < DEFAULT_CORE_FREQUENCY && + core_freq > DEFAULT_CORE_FREQUENCY) { + /* first, down to 250, then down to min */ + DELAY(TRANSITION_LATENCY); + bcm2835_cpufreq_set_clock_rate(sc, + BCM2835_MBOX_CLOCK_ID_CORE, + MHZ2HZ(DEFAULT_CORE_FREQUENCY)); + DELAY(TRANSITION_LATENCY); + /* reset core voltage */ + bcm2835_cpufreq_set_voltage(sc, + BCM2835_MBOX_VOLTAGE_ID_CORE, 0); + DELAY(TRANSITION_LATENCY); + } + bcm2835_cpufreq_set_clock_rate(sc, + BCM2835_MBOX_CLOCK_ID_CORE, + MHZ2HZ(sc->core_min_freq)); + DELAY(TRANSITION_LATENCY); + bcm2835_cpufreq_set_clock_rate(sc, + BCM2835_MBOX_CLOCK_ID_SDRAM, + MHZ2HZ(sc->sdram_min_freq)); + DELAY(TRANSITION_LATENCY); + } + } + + VC_UNLOCK(sc); + + if (resp_freq < 0 || arm_freq < 0 || resp_freq != arm_freq) { + device_printf(dev, "wrong freq\n"); + return (EIO); + } + DPRINTF("cpufreq: %d -> %d\n", cur_freq, arm_freq); + + return (0); +} + +static int +bcm2835_cpufreq_get(device_t dev, struct cf_setting *cf) +{ + struct bcm2835_cpufreq_softc *sc; + int arm_freq; + + if (cf == NULL) + return (EINVAL); + + sc = device_get_softc(dev); + memset(cf, CPUFREQ_VAL_UNKNOWN, sizeof(*cf)); + cf->dev = NULL; + + /* get cuurent value */ + VC_LOCK(sc); + arm_freq = bcm2835_cpufreq_get_clock_rate(sc, + BCM2835_MBOX_CLOCK_ID_ARM); + VC_UNLOCK(sc); + if (arm_freq < 0) { + device_printf(dev, "can't get clock\n"); + return (EINVAL); + } + + /* CPU clock in MHz or 100ths of a percent. */ + cf->freq = HZ2MHZ(arm_freq); + /* Voltage in mV. */ + cf->volts = CPUFREQ_VAL_UNKNOWN; + /* Power consumed in mW. */ + cf->power = CPUFREQ_VAL_UNKNOWN; + /* Transition latency in us. */ + cf->lat = TRANSITION_LATENCY; + /* Driver providing this setting. */ + cf->dev = dev; + + return (0); +} + +static int +bcm2835_cpufreq_make_freq_list(device_t dev, struct cf_setting *sets, + int *count) +{ + struct bcm2835_cpufreq_softc *sc; + int freq, min_freq, volts, rem; + int idx; + + sc = device_get_softc(dev); + freq = sc->arm_max_freq; + min_freq = sc->arm_min_freq; + + /* adjust head freq to STEP */ + rem = freq % MHZSTEP; + freq -= rem; + if (freq < min_freq) + freq = min_freq; + + /* if non-turbo, add extra low freq */ + if (sc->turbo_mode != BCM2835_MBOX_TURBO_ON) + if (min_freq > cpufreq_lowest_freq) + min_freq = cpufreq_lowest_freq; + + /* from freq to min_freq */ + for (idx = 0; idx < *count && freq >= min_freq; idx++) { + if (freq > sc->arm_min_freq) + volts = sc->max_voltage_core; + else + volts = sc->min_voltage_core; + sets[idx].freq = freq; + sets[idx].volts = volts; + sets[idx].lat = TRANSITION_LATENCY; + sets[idx].dev = dev; + freq -= MHZSTEP; + } + *count = ++idx; + + return (0); +} + +static int +bcm2835_cpufreq_settings(device_t dev, struct cf_setting *sets, int *count) +{ + struct bcm2835_cpufreq_softc *sc; + + if (sets == NULL || count == NULL) + return (EINVAL); + + sc = device_get_softc(dev); + if (sc->arm_min_freq < 0 || sc->arm_max_freq < 0) { + printf("device is not configured\n"); + return (EINVAL); + } + + /* fill data with unknown value */ + memset(sets, CPUFREQ_VAL_UNKNOWN, sizeof(*sets) * (*count)); + /* create new array up to count */ + bcm2835_cpufreq_make_freq_list(dev, sets, count); + + return (0); +} + +static int +bcm2835_cpufreq_type(device_t dev, int *type) +{ + + if (type == NULL) + return (EINVAL); + *type = CPUFREQ_TYPE_ABSOLUTE; + + return (0); +} + +static device_method_t bcm2835_cpufreq_methods[] = { + /* Device interface */ + DEVMETHOD(device_identify, bcm2835_cpufreq_identify), + DEVMETHOD(device_probe, bcm2835_cpufreq_probe), + DEVMETHOD(device_attach, bcm2835_cpufreq_attach), + DEVMETHOD(device_detach, bcm2835_cpufreq_detach), + + /* cpufreq interface */ + DEVMETHOD(cpufreq_drv_set, bcm2835_cpufreq_set), + DEVMETHOD(cpufreq_drv_get, bcm2835_cpufreq_get), + DEVMETHOD(cpufreq_drv_settings, bcm2835_cpufreq_settings), + DEVMETHOD(cpufreq_drv_type, bcm2835_cpufreq_type), + + DEVMETHOD_END +}; + +static devclass_t bcm2835_cpufreq_devclass; +static driver_t bcm2835_cpufreq_driver = { + "bcm2835_cpufreq", + bcm2835_cpufreq_methods, + sizeof(struct bcm2835_cpufreq_softc), +}; + +DRIVER_MODULE(bcm2835_cpufreq, cpu, bcm2835_cpufreq_driver, + bcm2835_cpufreq_devclass, 0, 0); Property changes on: stable/10/sys/arm/broadcom/bcm2835/bcm2835_cpufreq.c ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: stable/10/sys/arm/broadcom/bcm2835/bcm2835_mbox.c =================================================================== --- stable/10/sys/arm/broadcom/bcm2835/bcm2835_mbox.c (revision 278607) +++ stable/10/sys/arm/broadcom/bcm2835/bcm2835_mbox.c (revision 278608) @@ -1,251 +1,258 @@ /*- * Copyright (c) 2012 Oleksandr Tymoshenko * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include +#include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "mbox_if.h" #define REG_READ 0x00 #define REG_POL 0x10 #define REG_SENDER 0x14 #define REG_STATUS 0x18 #define STATUS_FULL 0x80000000 #define STATUS_EMPTY 0x40000000 #define REG_CONFIG 0x1C #define CONFIG_DATA_IRQ 0x00000001 #define REG_WRITE 0x20 /* This is Mailbox 1 address */ #define MBOX_MSG(chan, data) (((data) & ~0xf) | ((chan) & 0xf)) #define MBOX_CHAN(msg) ((msg) & 0xf) #define MBOX_DATA(msg) ((msg) & ~0xf) #define MBOX_LOCK(sc) do { \ mtx_lock(&(sc)->lock); \ } while(0) #define MBOX_UNLOCK(sc) do { \ mtx_unlock(&(sc)->lock); \ } while(0) +#undef DEBUG #ifdef DEBUG #define dprintf(fmt, args...) printf(fmt, ##args) #else #define dprintf(fmt, args...) #endif struct bcm_mbox_softc { struct mtx lock; struct resource * mem_res; struct resource * irq_res; void* intr_hl; bus_space_tag_t bst; bus_space_handle_t bsh; - int valid[BCM2835_MBOX_CHANS]; int msg[BCM2835_MBOX_CHANS]; + struct sema sema[BCM2835_MBOX_CHANS]; }; #define mbox_read_4(sc, reg) \ bus_space_read_4((sc)->bst, (sc)->bsh, reg) #define mbox_write_4(sc, reg, val) \ bus_space_write_4((sc)->bst, (sc)->bsh, reg, val) static void bcm_mbox_intr(void *arg) { struct bcm_mbox_softc *sc = arg; int chan; uint32_t data; uint32_t msg; - MBOX_LOCK(sc); while (!(mbox_read_4(sc, REG_STATUS) & STATUS_EMPTY)) { msg = mbox_read_4(sc, REG_READ); dprintf("bcm_mbox_intr: raw data %08x\n", msg); chan = MBOX_CHAN(msg); data = MBOX_DATA(msg); - if (sc->valid[chan]) { + if (sc->msg[chan]) { printf("bcm_mbox_intr: channel %d oveflow\n", chan); continue; } dprintf("bcm_mbox_intr: chan %d, data %08x\n", chan, data); - sc->msg[chan] = data; - sc->valid[chan] = 1; - wakeup(&sc->msg[chan]); - + sc->msg[chan] = msg; + sema_post(&sc->sema[chan]); } - MBOX_UNLOCK(sc); } static int bcm_mbox_probe(device_t dev) { if (!ofw_bus_status_okay(dev)) return (ENXIO); if (ofw_bus_is_compatible(dev, "broadcom,bcm2835-mbox")) { device_set_desc(dev, "BCM2835 VideoCore Mailbox"); return(BUS_PROBE_DEFAULT); } return (ENXIO); } static int bcm_mbox_attach(device_t dev) { struct bcm_mbox_softc *sc = device_get_softc(dev); int i; int rid = 0; sc->mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, RF_ACTIVE); if (sc->mem_res == NULL) { device_printf(dev, "could not allocate memory resource\n"); return (ENXIO); } sc->bst = rman_get_bustag(sc->mem_res); sc->bsh = rman_get_bushandle(sc->mem_res); rid = 0; sc->irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, RF_ACTIVE); if (sc->irq_res == NULL) { device_printf(dev, "could not allocate interrupt resource\n"); return (ENXIO); } /* Setup and enable the timer */ if (bus_setup_intr(dev, sc->irq_res, INTR_MPSAFE | INTR_TYPE_MISC, NULL, bcm_mbox_intr, sc, &sc->intr_hl) != 0) { bus_release_resource(dev, SYS_RES_IRQ, rid, sc->irq_res); device_printf(dev, "Unable to setup the clock irq handler.\n"); return (ENXIO); } mtx_init(&sc->lock, "vcio mbox", NULL, MTX_DEF); for (i = 0; i < BCM2835_MBOX_CHANS; i++) { - sc->valid[0] = 0; - sc->msg[0] = 0; + sc->msg[i] = 0; + sema_init(&sc->sema[i], 0, "mbox"); } /* Read all pending messages */ - bcm_mbox_intr(sc); + while ((mbox_read_4(sc, REG_STATUS) & STATUS_EMPTY) == 0) + (void)mbox_read_4(sc, REG_READ); mbox_write_4(sc, REG_CONFIG, CONFIG_DATA_IRQ); return (0); } /* * Mailbox API */ static int bcm_mbox_write(device_t dev, int chan, uint32_t data) { int limit = 20000; struct bcm_mbox_softc *sc = device_get_softc(dev); dprintf("bcm_mbox_write: chan %d, data %08x\n", chan, data); MBOX_LOCK(sc); while ((mbox_read_4(sc, REG_STATUS) & STATUS_FULL) && limit--) { DELAY(2); } if (limit == 0) { printf("bcm_mbox_write: STATUS_FULL stuck"); MBOX_UNLOCK(sc); return (EAGAIN); } mbox_write_4(sc, REG_WRITE, MBOX_MSG(chan, data)); MBOX_UNLOCK(sc); return (0); } static int bcm_mbox_read(device_t dev, int chan, uint32_t *data) { struct bcm_mbox_softc *sc = device_get_softc(dev); dprintf("bcm_mbox_read: chan %d\n", chan); MBOX_LOCK(sc); - while (!sc->valid[chan]) - msleep(&sc->msg[chan], &sc->lock, PZERO, "vcio mbox read", 0); - *data = sc->msg[chan]; - sc->valid[chan] = 0; + while (sema_trywait(&sc->sema[chan]) == 0) { + /* do not unlock sc while waiting for the mbox */ + if (sema_timedwait(&sc->sema[chan], 10*hz) == 0) + break; + printf("timeout sema for chan %d\n", chan); + } + /* + * get data from intr handler, the same channel is never coming + * because of holding sc lock. + */ + *data = MBOX_DATA(sc->msg[chan]); + sc->msg[chan] = 0; MBOX_UNLOCK(sc); dprintf("bcm_mbox_read: chan %d, data %08x\n", chan, *data); return (0); } static device_method_t bcm_mbox_methods[] = { DEVMETHOD(device_probe, bcm_mbox_probe), DEVMETHOD(device_attach, bcm_mbox_attach), DEVMETHOD(mbox_read, bcm_mbox_read), DEVMETHOD(mbox_write, bcm_mbox_write), DEVMETHOD_END }; static driver_t bcm_mbox_driver = { "mbox", bcm_mbox_methods, sizeof(struct bcm_mbox_softc), }; static devclass_t bcm_mbox_devclass; DRIVER_MODULE(mbox, simplebus, bcm_mbox_driver, bcm_mbox_devclass, 0, 0); Index: stable/10/sys/arm/broadcom/bcm2835/bcm2835_mbox.h =================================================================== --- stable/10/sys/arm/broadcom/bcm2835/bcm2835_mbox.h (revision 278607) +++ stable/10/sys/arm/broadcom/bcm2835/bcm2835_mbox.h (revision 278608) @@ -1,41 +1,42 @@ /*- * Copyright (c) 2012 Oleksandr Tymoshenko * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * $FreeBSD$ */ #ifndef _BCM2835_MBOX_H_ #define _BCM2835_MBOX_H_ #define BCM2835_MBOX_CHAN_POWER 0 #define BCM2835_MBOX_CHAN_FB 1 #define BCM2835_MBOX_CHAN_VUART 2 #define BCM2835_MBOX_CHAN_VCHIQ 3 #define BCM2835_MBOX_CHAN_LEDS 4 #define BCM2835_MBOX_CHAN_BUTTONS 5 #define BCM2835_MBOX_CHAN_TS 6 -#define BCM2835_MBOX_CHANS 7 +#define BCM2835_MBOX_CHAN_PROP 8 +#define BCM2835_MBOX_CHANS 9 #endif /* _BCM2835_MBOX_H_ */ Index: stable/10/sys/arm/broadcom/bcm2835/bcm2835_mbox_prop.h =================================================================== --- stable/10/sys/arm/broadcom/bcm2835/bcm2835_mbox_prop.h (nonexistent) +++ stable/10/sys/arm/broadcom/bcm2835/bcm2835_mbox_prop.h (revision 278608) @@ -0,0 +1,273 @@ +/*- + * Copyright (C) 2013-2014 Daisuke Aoyama + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD$ + */ + +#ifndef _BCM2835_MBOX_PROP_H_ +#define _BCM2835_MBOX_PROP_H_ + +#include +#include + +/* + * Mailbox property interface: + * https://github.com/raspberrypi/firmware/wiki/Mailbox-property-interface + */ +#define BCM2835_MBOX_CODE_REQ 0 +#define BCM2835_MBOX_CODE_RESP_SUCCESS 0x80000000 +#define BCM2835_MBOX_CODE_RESP_ERROR 0x80000001 +#define BCM2835_MBOX_TAG_VAL_LEN_RESPONSE 0x80000000 + +struct bcm2835_mbox_hdr { + uint32_t buf_size; + uint32_t code; +}; + +struct bcm2835_mbox_tag_hdr { + uint32_t tag; + uint32_t val_buf_size; + uint32_t val_len; +}; + +#define BCM2835_MBOX_CLOCK_ID_EMMC 0x00000001 +#define BCM2835_MBOX_CLOCK_ID_UART 0x00000002 +#define BCM2835_MBOX_CLOCK_ID_ARM 0x00000003 +#define BCM2835_MBOX_CLOCK_ID_CORE 0x00000004 +#define BCM2835_MBOX_CLOCK_ID_V3D 0x00000005 +#define BCM2835_MBOX_CLOCK_ID_H264 0x00000006 +#define BCM2835_MBOX_CLOCK_ID_ISP 0x00000007 +#define BCM2835_MBOX_CLOCK_ID_SDRAM 0x00000008 +#define BCM2835_MBOX_CLOCK_ID_PIXEL 0x00000009 +#define BCM2835_MBOX_CLOCK_ID_PWM 0x0000000a + +#define BCM2835_MBOX_TAG_GET_CLOCK_RATE 0x00030002 +#define BCM2835_MBOX_TAG_SET_CLOCK_RATE 0x00038002 +#define BCM2835_MBOX_TAG_GET_MAX_CLOCK_RATE 0x00030004 +#define BCM2835_MBOX_TAG_GET_MIN_CLOCK_RATE 0x00030007 + +struct msg_get_clock_rate { + struct bcm2835_mbox_hdr hdr; + struct bcm2835_mbox_tag_hdr tag_hdr; + union { + struct { + uint32_t clock_id; + } req; + struct { + uint32_t clock_id; + uint32_t rate_hz; + } resp; + } body; + uint32_t end_tag; +}; + +struct msg_set_clock_rate { + struct bcm2835_mbox_hdr hdr; + struct bcm2835_mbox_tag_hdr tag_hdr; + union { + struct { + uint32_t clock_id; + uint32_t rate_hz; + } req; + struct { + uint32_t clock_id; + uint32_t rate_hz; + } resp; + } body; + uint32_t end_tag; +}; + +struct msg_get_max_clock_rate { + struct bcm2835_mbox_hdr hdr; + struct bcm2835_mbox_tag_hdr tag_hdr; + union { + struct { + uint32_t clock_id; + } req; + struct { + uint32_t clock_id; + uint32_t rate_hz; + } resp; + } body; + uint32_t end_tag; +}; + +struct msg_get_min_clock_rate { + struct bcm2835_mbox_hdr hdr; + struct bcm2835_mbox_tag_hdr tag_hdr; + union { + struct { + uint32_t clock_id; + } req; + struct { + uint32_t clock_id; + uint32_t rate_hz; + } resp; + } body; + uint32_t end_tag; +}; + +#define BCM2835_MBOX_TURBO_ON 1 +#define BCM2835_MBOX_TURBO_OFF 0 + +#define BCM2835_MBOX_TAG_GET_TURBO 0x00030009 +#define BCM2835_MBOX_TAG_SET_TURBO 0x00038009 + +struct msg_get_turbo { + struct bcm2835_mbox_hdr hdr; + struct bcm2835_mbox_tag_hdr tag_hdr; + union { + struct { + uint32_t id; + } req; + struct { + uint32_t id; + uint32_t level; + } resp; + } body; + uint32_t end_tag; +}; + +struct msg_set_turbo { + struct bcm2835_mbox_hdr hdr; + struct bcm2835_mbox_tag_hdr tag_hdr; + union { + struct { + uint32_t id; + uint32_t level; + } req; + struct { + uint32_t id; + uint32_t level; + } resp; + } body; + uint32_t end_tag; +}; + +#define BCM2835_MBOX_VOLTAGE_ID_CORE 0x00000001 +#define BCM2835_MBOX_VOLTAGE_ID_SDRAM_C 0x00000002 +#define BCM2835_MBOX_VOLTAGE_ID_SDRAM_P 0x00000003 +#define BCM2835_MBOX_VOLTAGE_ID_SDRAM_I 0x00000004 + +#define BCM2835_MBOX_TAG_GET_VOLTAGE 0x00030003 +#define BCM2835_MBOX_TAG_SET_VOLTAGE 0x00038003 +#define BCM2835_MBOX_TAG_GET_MAX_VOLTAGE 0x00030005 +#define BCM2835_MBOX_TAG_GET_MIN_VOLTAGE 0x00030008 + +struct msg_get_voltage { + struct bcm2835_mbox_hdr hdr; + struct bcm2835_mbox_tag_hdr tag_hdr; + union { + struct { + uint32_t voltage_id; + } req; + struct { + uint32_t voltage_id; + uint32_t value; + } resp; + } body; + uint32_t end_tag; +}; + +struct msg_set_voltage { + struct bcm2835_mbox_hdr hdr; + struct bcm2835_mbox_tag_hdr tag_hdr; + union { + struct { + uint32_t voltage_id; + uint32_t value; + } req; + struct { + uint32_t voltage_id; + uint32_t value; + } resp; + } body; + uint32_t end_tag; +}; + +struct msg_get_max_voltage { + struct bcm2835_mbox_hdr hdr; + struct bcm2835_mbox_tag_hdr tag_hdr; + union { + struct { + uint32_t voltage_id; + } req; + struct { + uint32_t voltage_id; + uint32_t value; + } resp; + } body; + uint32_t end_tag; +}; + +struct msg_get_min_voltage { + struct bcm2835_mbox_hdr hdr; + struct bcm2835_mbox_tag_hdr tag_hdr; + union { + struct { + uint32_t voltage_id; + } req; + struct { + uint32_t voltage_id; + uint32_t value; + } resp; + } body; + uint32_t end_tag; +}; + +#define BCM2835_MBOX_TAG_GET_TEMPERATURE 0x00030006 +#define BCM2835_MBOX_TAG_GET_MAX_TEMPERATURE 0x0003000a + +struct msg_get_temperature { + struct bcm2835_mbox_hdr hdr; + struct bcm2835_mbox_tag_hdr tag_hdr; + union { + struct { + uint32_t temperature_id; + } req; + struct { + uint32_t temperature_id; + uint32_t value; + } resp; + } body; + uint32_t end_tag; +}; + +struct msg_get_max_temperature { + struct bcm2835_mbox_hdr hdr; + struct bcm2835_mbox_tag_hdr tag_hdr; + union { + struct { + uint32_t temperature_id; + } req; + struct { + uint32_t temperature_id; + uint32_t value; + } resp; + } body; + uint32_t end_tag; +}; + +#endif /* _BCM2835_MBOX_PROP_H_ */ Property changes on: stable/10/sys/arm/broadcom/bcm2835/bcm2835_mbox_prop.h ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: stable/10/sys/arm/broadcom/bcm2835/files.bcm2835 =================================================================== --- stable/10/sys/arm/broadcom/bcm2835/files.bcm2835 (revision 278607) +++ stable/10/sys/arm/broadcom/bcm2835/files.bcm2835 (revision 278608) @@ -1,28 +1,30 @@ # $FreeBSD$ arm/broadcom/bcm2835/bcm2835_bsc.c optional bcm2835_bsc arm/broadcom/bcm2835/bcm2835_common.c optional fdt +arm/broadcom/bcm2835/bcm2835_cpufreq.c standard arm/broadcom/bcm2835/bcm2835_dma.c standard arm/broadcom/bcm2835/bcm2835_fb.c optional sc arm/broadcom/bcm2835/bcm2835_fbd.c optional vt arm/broadcom/bcm2835/bcm2835_gpio.c optional gpio arm/broadcom/bcm2835/bcm2835_intr.c standard arm/broadcom/bcm2835/bcm2835_machdep.c standard arm/broadcom/bcm2835/bcm2835_mbox.c standard arm/broadcom/bcm2835/bcm2835_sdhci.c optional sdhci arm/broadcom/bcm2835/bcm2835_spi.c optional bcm2835_spi arm/broadcom/bcm2835/bcm2835_systimer.c standard arm/broadcom/bcm2835/bcm2835_wdog.c standard dev/usb/controller/dwc_otg_fdt.c optional dwcotg arm/arm/bus_space-v6.c standard arm/arm/bus_space_generic.c standard arm/arm/bus_space_asm_generic.S standard arm/arm/cpufunc_asm_arm11.S standard arm/arm/cpufunc_asm_arm11x6.S standard arm/arm/cpufunc_asm_armv5.S standard arm/arm/cpufunc_asm_armv6.S standard kern/kern_clocksource.c standard dev/mbox/mbox_if.m standard +dev/ofw/ofw_cpu.c standard Index: stable/10/sys/boot/fdt/dts/arm/rpi.dts =================================================================== --- stable/10/sys/boot/fdt/dts/arm/rpi.dts (revision 278607) +++ stable/10/sys/boot/fdt/dts/arm/rpi.dts (revision 278608) @@ -1,381 +1,392 @@ /* * Copyright (c) 2012 Oleksandr Tymoshenko * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * $FreeBSD$ */ /dts-v1/; /include/ "bcm2835.dtsi" / { model = "Raspberry Pi (BCM2835)"; compatible = "raspberrypi,model-a", "raspberrypi,model-b", "broadcom,bcm2835-vc", "broadcom,bcm2708-vc"; memreserve = <0x08000000 0x08000000>; /* Set by VideoCore */ + cpus { + #address-cells = <1>; + #size-cells = <0>; + cpu@0 { + compatible = "arm,1176jzf-s"; + device_type = "cpu"; + reg = <0>; /* CPU ID=0 */ + clock-frequency = <700000000>; /* 700MHz */ + }; + }; + memory { device_type = "memory"; reg = <0 0x8000000>; /* 128MB, Set by VideoCore */ }; system { revision = <0>; /* Set by VideoCore */ serial = <0 0>; /* Set by VideoCore */ }; axi { gpio: gpio { /* BSC0 */ pins_bsc0_a: bsc0_a { broadcom,function = "ALT0"; }; pins_bsc0_b: bsc0_b { broadcom,function = "ALT0"; }; pins_bsc0_c: bsc0_c { broadcom,function = "ALT1"; }; /* BSC1 */ pins_bsc1_a: bsc1_a { broadcom,function = "ALT0"; }; pins_bsc1_b: bsc1_b { broadcom,function = "ALT2"; }; /* GPCLK0 */ pins_gpclk0_a: gpclk0_a { broadcom,function = "ALT0"; }; pins_gpclk0_b: gpclk0_b { broadcom,function = "ALT5"; }; pins_gpclk0_c: gpclk0_c { broadcom,function = "ALT0"; }; pins_gpclk0_d: gpclk0_d { broadcom,function = "ALT0"; }; /* GPCLK1 */ pins_gpclk1_a: gpclk1_a { broadcom,function = "ALT0"; }; pins_gpclk1_b: gpclk1_b { broadcom,function = "ALT5"; }; pins_gpclk1_c: gpclk1_c { broadcom,function = "ALT0"; }; pins_gpclk1_d: gpclk1_d { broadcom,function = "ALT0"; }; /* GPCLK2 */ pins_gpclk2_a: gpclk2_a { broadcom,function = "ALT0"; }; pins_gpclk2_b: gpclk2_b { broadcom,function = "ALT0"; }; /* SPI0 */ pins_spi0_a: spi0_a { broadcom,function = "ALT0"; }; pins_spi0_b: spi0_b { broadcom,function = "ALT0"; }; /* PWM */ pins_pwm0_a: pwm0_a { broadcom,function = "ALT0"; }; pins_pwm0_b: pwm0_b { broadcom,function = "ALT5"; }; pins_pwm0_c: pwm0_c { broadcom,function = "ALT0"; }; pins_pwm1_a: pwm1_a { broadcom,function = "ALT0"; }; pins_pwm1_b: pwm1_b { broadcom,function = "ALT5"; }; pins_pwm1_c: pwm1_c { broadcom,function = "ALT0"; }; pins_pwm1_d: pwm1_d { broadcom,function = "ALT0"; }; /* UART0 */ pins_uart0_a: uart0_a { broadcom,function = "ALT0"; }; pins_uart0_b: uart0_b { broadcom,function = "ALT3"; }; pins_uart0_c: uart0_c { broadcom,function = "ALT2"; }; pins_uart0_fc_a: uart0_fc_a { broadcom,function = "ALT3"; }; pins_uart0_fc_b: uart0_fc_b { broadcom,function = "ALT3"; }; pins_uart0_fc_c: uart0_fc_c { broadcom,function = "ALT2"; }; /* PCM */ pins_pcm_a: pcm_a { broadcom,function = "ALT0"; }; pins_pcm_b: pcm_b { broadcom,function = "ALT2"; }; /* Secondary Address Bus */ pins_sm_addr_a: sm_addr_a { broadcom,function = "ALT1"; }; pins_sm_addr_b: sm_addr_b { broadcom,function = "ALT1"; }; pins_sm_ctl_a: sm_ctl_a { broadcom,function = "ALT1"; }; pins_sm_ctl_b: sm_ctl_b { broadcom,function = "ALT1"; }; pins_sm_data_8bit_a: sm_data_8bit_a { broadcom,function = "ALT1"; }; pins_sm_data_8bit_b: sm_data_8bit_b { broadcom,function = "ALT1"; }; pins_sm_data_16bit: sm_data_16bit { broadcom,function = "ALT1"; }; pins_sm_data_18bit: sm_data_18bit { broadcom,function = "ALT1"; }; /* BSCSL */ pins_bscsl: bscsl { broadcom,function = "ALT3"; }; /* SPISL */ pins_spisl: spisl { broadcom,function = "ALT3"; }; /* SPI1 */ pins_spi1: spi1 { broadcom,function = "ALT4"; }; /* UART1 */ pins_uart1_a: uart1_a { broadcom,function = "ALT5"; }; pins_uart1_b: uart1_b { broadcom,function = "ALT5"; }; pins_uart1_c: uart1_c { broadcom,function = "ALT5"; }; pins_uart1_fc_a: uart1_fc_a { broadcom,function = "ALT5"; }; pins_uart1_fc_b: uart1_fc_b { broadcom,function = "ALT5"; }; pins_uart1_fc_c: uart1_fc_c { broadcom,function = "ALT5"; }; /* SPI2 */ pins_spi2: spi2 { broadcom,function = "ALT4"; }; /* ARM JTAG */ pins_arm_jtag_trst: arm_jtag_trst { broadcom,function = "ALT4"; }; pins_arm_jtag_a: arm_jtag_a { broadcom,function = "ALT5"; }; pins_arm_jtag_b: arm_jtag_b { broadcom,function = "ALT4"; }; /* Reserved */ pins_reserved: reserved { broadcom,function = "ALT3"; }; }; usb { hub { compatible = "usb,hub", "usb,device"; reg = <0x00000001>; #address-cells = <1>; #size-cells = <0>; ethernet { compatible = "net,ethernet", "usb,device"; reg = <0x00000001>; mac-address = [00 00 00 00 00 00]; }; }; }; }; display { compatible = "broadcom,bcm2835-fb", "broadcom,bcm2708-fb"; broadcom,vc-mailbox = <&vc_mbox>; broadcom,vc-channel = <1>; broadcom,width = <0>; /* Set by VideoCore */ broadcom,height = <0>; /* Set by VideoCore */ broadcom,depth = <0>; /* Set by VideoCore */ }; leds { compatible = "gpio-leds"; ok { label = "ok"; gpios = <&gpio 16 1>; /* Don't change this - it configures * how the led driver determines if * the led is on or off when it loads. */ default-state = "keep"; /* This is the real default state. */ linux,default-trigger = "default-on"; }; }; power: regulator { compatible = "broadcom,bcm2835-power-mgr", "broadcom,bcm2708-power-mgr", "simple-bus"; #address-cells = <1>; #size-cells = <0>; broadcom,vc-mailbox = <&vc_mbox>; broadcom,vc-channel = <0>; regulator-name = "VideoCore"; regulator-min-microvolt = <5000000>; regulator-max-microvolt = <5000000>; regulator-always-on = <1>; sd_card_power: regulator@0 { compatible = "broadcom,bcm2835-power-dev", "broadcom,bcm2708-power-dev"; reg = <0>; vin-supply = <&power>; regulator-name = "SD Card"; regulator-min-microvolt = <3300000>; regulator-max-microvolt = <3300000>; }; /* This is for the controller itself, not the root port */ usb_hcd_power: regulator@3 { compatible = "broadcom,bcm2835-power-dev", "broadcom,bcm2708-power-dev"; reg = <3>; vin-supply = <&power>; regulator-name = "USB HCD"; regulator-min-microvolt = <5000000>; regulator-max-microvolt = <5000000>; }; }; aliases { uart0 = &uart0; }; chosen { bootargs = ""; /* Set by VideoCore */ stdin = "uart0"; stdout = "uart0"; }; }; Index: stable/10/sys/conf/files.powerpc =================================================================== --- stable/10/sys/conf/files.powerpc (revision 278607) +++ stable/10/sys/conf/files.powerpc (revision 278608) @@ -1,247 +1,247 @@ # This file tells config what files go into building a kernel, # files marked standard are always included. # # $FreeBSD$ # # The long compile-with and dependency lines are required because of # limitations in config: backslash-newline doesn't work in strings, and # dependency lines other than the first are silently ignored. # # font.h optional sc \ compile-with "uudecode < /usr/share/syscons/fonts/${SC_DFLT_FONT}-8x16.fnt && file2c 'u_char dflt_font_16[16*256] = {' '};' < ${SC_DFLT_FONT}-8x16 > font.h && uudecode < /usr/share/syscons/fonts/${SC_DFLT_FONT}-8x14.fnt && file2c 'u_char dflt_font_14[14*256] = {' '};' < ${SC_DFLT_FONT}-8x14 >> font.h && uudecode < /usr/share/syscons/fonts/${SC_DFLT_FONT}-8x8.fnt && file2c 'u_char dflt_font_8[8*256] = {' '};' < ${SC_DFLT_FONT}-8x8 >> font.h" \ no-obj no-implicit-rule before-depend \ clean "font.h ${SC_DFLT_FONT}-8x14 ${SC_DFLT_FONT}-8x16 ${SC_DFLT_FONT}-8x8" # # There is only an asm version on ppc64. cddl/compat/opensolaris/kern/opensolaris_atomic.c optional zfs powerpc compile-with "${ZFS_C}" cddl/contrib/opensolaris/common/atomic/powerpc64/opensolaris_atomic.S optional zfs powerpc64 compile-with "${ZFS_S}" crypto/blowfish/bf_enc.c optional crypto | ipsec crypto/des/des_enc.c optional crypto | ipsec | netsmb dev/bm/if_bm.c optional bm powermac dev/adb/adb_bus.c optional adb dev/adb/adb_kbd.c optional adb dev/adb/adb_mouse.c optional adb dev/adb/adb_hb_if.m optional adb dev/adb/adb_if.m optional adb dev/adb/adb_buttons.c optional adb dev/agp/agp_apple.c optional agp powermac dev/fb/fb.c optional sc dev/fdt/fdt_powerpc.c optional fdt dev/hwpmc/hwpmc_powerpc.c optional hwpmc dev/hwpmc/hwpmc_mpc7xxx.c optional hwpmc dev/hwpmc/hwpmc_ppc970.c optional hwpmc dev/iicbus/ad7417.c optional ad7417 powermac dev/iicbus/adt746x.c optional adt746x powermac dev/iicbus/ds1631.c optional ds1631 powermac dev/iicbus/ds1775.c optional ds1775 powermac dev/iicbus/max6690.c optional max6690 powermac dev/kbd/kbd.c optional sc | vt dev/nand/nfc_fsl.c optional nand mpc85xx # ofw can be either aim or fdt: fdt case handled in files. aim only powerpc specific. dev/ofw/openfirm.c optional aim dev/ofw/openfirmio.c optional aim dev/ofw/ofw_bus_if.m optional aim +dev/ofw/ofw_cpu.c optional aim dev/ofw/ofw_if.m optional aim dev/ofw/ofw_bus_subr.c optional aim dev/ofw/ofw_console.c optional aim dev/ofw/ofw_disk.c optional ofwd aim dev/ofw/ofw_iicbus.c optional iicbus aim dev/ofw/ofwbus.c optional aim | fdt dev/ofw/ofw_standard.c optional aim powerpc dev/powermac_nvram/powermac_nvram.c optional powermac_nvram powermac dev/quicc/quicc_bfe_fdt.c optional quicc mpc85xx dev/scc/scc_bfe_macio.c optional scc powermac dev/sec/sec.c optional sec mpc85xx dev/sound/macio/aoa.c optional snd_davbus | snd_ai2s powermac dev/sound/macio/davbus.c optional snd_davbus powermac dev/sound/macio/i2s.c optional snd_ai2s powermac dev/sound/macio/onyx.c optional snd_ai2s iicbus powermac dev/sound/macio/snapper.c optional snd_ai2s iicbus powermac dev/sound/macio/tumbler.c optional snd_ai2s iicbus powermac dev/syscons/scgfbrndr.c optional sc dev/syscons/scterm-teken.c optional sc dev/syscons/scvtb.c optional sc dev/tsec/if_tsec.c optional tsec dev/tsec/if_tsec_fdt.c optional tsec fdt dev/uart/uart_cpu_powerpc.c optional uart dev/usb/controller/ehci_fsl.c optional ehci mpc85xx dev/vt/hw/ofwfb/ofwfb.c optional vt aim kern/kern_clocksource.c standard kern/subr_dummy_vdso_tc.c standard kern/syscalls.c optional ktr libkern/ashldi3.c optional powerpc libkern/ashrdi3.c optional powerpc libkern/bcmp.c standard libkern/cmpdi2.c optional powerpc libkern/divdi3.c optional powerpc libkern/ffs.c standard libkern/ffsl.c standard libkern/fls.c standard libkern/flsl.c standard libkern/lshrdi3.c optional powerpc libkern/memmove.c standard libkern/memset.c standard libkern/moddi3.c optional powerpc libkern/qdivrem.c optional powerpc libkern/ucmpdi2.c optional powerpc libkern/udivdi3.c optional powerpc libkern/umoddi3.c optional powerpc powerpc/aim/interrupt.c optional aim powerpc/aim/locore.S optional aim no-obj powerpc/aim/machdep.c optional aim powerpc/aim/mmu_oea.c optional aim powerpc powerpc/aim/mmu_oea64.c optional aim powerpc/aim/moea64_if.m optional aim powerpc/aim/moea64_native.c optional aim powerpc/aim/mp_cpudep.c optional aim powerpc/aim/slb.c optional aim powerpc64 powerpc/aim/trap.c optional aim powerpc/aim/uma_machdep.c optional aim powerpc/booke/interrupt.c optional booke powerpc/booke/locore.S optional booke no-obj powerpc/booke/machdep.c optional booke powerpc/booke/machdep_e500.c optional booke_e500 powerpc/booke/mp_cpudep.c optional booke smp powerpc/booke/platform_bare.c optional booke powerpc/booke/pmap.c optional booke powerpc/booke/trap.c optional booke powerpc/cpufreq/dfs.c optional cpufreq powerpc/cpufreq/pcr.c optional cpufreq aim powerpc/cpufreq/pmufreq.c optional cpufreq aim pmu powerpc/fpu/fpu_add.c optional fpu_emu powerpc/fpu/fpu_compare.c optional fpu_emu powerpc/fpu/fpu_div.c optional fpu_emu powerpc/fpu/fpu_emu.c optional fpu_emu powerpc/fpu/fpu_explode.c optional fpu_emu powerpc/fpu/fpu_implode.c optional fpu_emu powerpc/fpu/fpu_mul.c optional fpu_emu powerpc/fpu/fpu_sqrt.c optional fpu_emu powerpc/fpu/fpu_subr.c optional fpu_emu powerpc/mambo/mambocall.S optional mambo powerpc/mambo/mambo.c optional mambo powerpc/mambo/mambo_console.c optional mambo powerpc/mambo/mambo_disk.c optional mambo powerpc/mpc85xx/atpic.c optional mpc85xx isa powerpc/mpc85xx/ds1553_bus_fdt.c optional ds1553 fdt powerpc/mpc85xx/ds1553_core.c optional ds1553 powerpc/mpc85xx/i2c.c optional iicbus fdt powerpc/mpc85xx/isa.c optional mpc85xx isa powerpc/mpc85xx/lbc.c optional mpc85xx powerpc/mpc85xx/mpc85xx.c optional mpc85xx powerpc/mpc85xx/platform_mpc85xx.c optional mpc85xx powerpc/mpc85xx/pci_mpc85xx.c optional pci mpc85xx -powerpc/ofw/ofw_cpu.c optional aim powerpc/ofw/ofw_machdep.c standard powerpc/ofw/ofw_pci.c optional pci powerpc/ofw/ofw_pcibus.c optional pci powerpc/ofw/ofw_pcib_pci.c optional pci powerpc/ofw/ofw_real.c optional aim powerpc/ofw/ofw_syscons.c optional sc aim powerpc/ofw/ofwcall32.S optional aim powerpc powerpc/ofw/ofwcall64.S optional aim powerpc64 powerpc/ofw/ofwmagic.S optional aim powerpc/ofw/openpic_ofw.c optional aim | fdt powerpc/ofw/rtas.c optional aim powerpc/powermac/ata_kauai.c optional powermac ata | powermac atamacio powerpc/powermac/ata_macio.c optional powermac ata | powermac atamacio powerpc/powermac/ata_dbdma.c optional powermac ata | powermac atamacio powerpc/powermac/atibl.c optional powermac atibl powerpc/powermac/cuda.c optional powermac cuda powerpc/powermac/cpcht.c optional powermac pci powerpc/powermac/dbdma.c optional powermac pci powerpc/powermac/fcu.c optional powermac fcu powerpc/powermac/grackle.c optional powermac pci powerpc/powermac/hrowpic.c optional powermac pci powerpc/powermac/kiic.c optional powermac kiic powerpc/powermac/macgpio.c optional powermac pci powerpc/powermac/macio.c optional powermac pci powerpc/powermac/nvbl.c optional powermac nvbl powerpc/powermac/platform_powermac.c optional powermac powerpc/powermac/powermac_thermal.c optional powermac powerpc/powermac/pswitch.c optional powermac pswitch powerpc/powermac/pmu.c optional powermac pmu powerpc/powermac/smu.c optional powermac smu powerpc/powermac/smusat.c optional powermac smu powerpc/powermac/uninorth.c optional powermac powerpc/powermac/uninorthpci.c optional powermac pci powerpc/powermac/vcoregpio.c optional powermac powerpc/powermac/windtunnel.c optional powermac windtunnel powerpc/powerpc/altivec.c standard powerpc/powerpc/autoconf.c standard powerpc/powerpc/bcopy.c standard powerpc/powerpc/bus_machdep.c standard powerpc/powerpc/busdma_machdep.c standard powerpc/powerpc/clock.c standard powerpc/powerpc/copyinout.c standard powerpc/powerpc/copystr.c standard powerpc/powerpc/cpu.c standard powerpc/powerpc/db_disasm.c optional ddb powerpc/powerpc/db_hwwatch.c optional ddb powerpc/powerpc/db_interface.c optional ddb powerpc/powerpc/db_trace.c optional ddb powerpc/powerpc/dump_machdep.c standard powerpc/powerpc/elf32_machdep.c optional powerpc | compat_freebsd32 powerpc/powerpc/elf64_machdep.c optional powerpc64 powerpc/powerpc/exec_machdep.c standard powerpc/powerpc/fpu.c standard powerpc/powerpc/fuswintr.c standard powerpc/powerpc/gdb_machdep.c optional gdb powerpc/powerpc/in_cksum.c optional inet | inet6 powerpc/powerpc/intr_machdep.c standard powerpc/powerpc/iommu_if.m standard powerpc/powerpc/mem.c optional mem powerpc/powerpc/mmu_if.m standard powerpc/powerpc/mp_machdep.c optional smp powerpc/powerpc/nexus.c standard powerpc/powerpc/openpic.c standard powerpc/powerpc/pic_if.m standard powerpc/powerpc/pmap_dispatch.c standard powerpc/powerpc/platform.c standard powerpc/powerpc/platform_if.m standard powerpc/powerpc/sc_machdep.c optional sc powerpc/powerpc/setjmp.S standard powerpc/powerpc/sigcode32.S optional powerpc | compat_freebsd32 powerpc/powerpc/sigcode64.S optional powerpc64 powerpc/powerpc/swtch32.S optional powerpc powerpc/powerpc/swtch64.S optional powerpc64 powerpc/powerpc/stack_machdep.c optional ddb | stack powerpc/powerpc/suswintr.c standard powerpc/powerpc/syncicache.c standard powerpc/powerpc/sys_machdep.c standard powerpc/powerpc/uio_machdep.c standard powerpc/powerpc/vm_machdep.c standard powerpc/ps3/ehci_ps3.c optional ps3 ehci powerpc/ps3/ohci_ps3.c optional ps3 ohci powerpc/ps3/if_glc.c optional ps3 glc powerpc/ps3/mmu_ps3.c optional ps3 powerpc/ps3/platform_ps3.c optional ps3 powerpc/ps3/ps3bus.c optional ps3 powerpc/ps3/ps3cdrom.c optional ps3 scbus powerpc/ps3/ps3disk.c optional ps3 powerpc/ps3/ps3pic.c optional ps3 powerpc/ps3/ps3_syscons.c optional ps3 vt powerpc/ps3/ps3-hvcall.S optional ps3 powerpc/pseries/phyp-hvcall.S optional pseries powerpc64 powerpc/pseries/mmu_phyp.c optional pseries powerpc64 powerpc/pseries/phyp_console.c optional pseries powerpc64 uart powerpc/pseries/phyp_llan.c optional llan powerpc/pseries/phyp_vscsi.c optional pseries powerpc64 scbus powerpc/pseries/platform_chrp.c optional pseries powerpc/pseries/plpar_iommu.c optional pseries powerpc64 powerpc/pseries/plpar_pcibus.c optional pseries powerpc64 pci powerpc/pseries/rtas_dev.c optional pseries powerpc/pseries/rtas_pci.c optional pseries pci powerpc/pseries/vdevice.c optional pseries powerpc64 powerpc/pseries/xics.c optional pseries powerpc64 powerpc/psim/iobus.c optional psim powerpc/psim/ata_iobus.c optional ata psim powerpc/psim/openpic_iobus.c optional psim powerpc/psim/uart_iobus.c optional uart psim powerpc/wii/platform_wii.c optional wii powerpc/wii/wii_bus.c optional wii powerpc/wii/wii_pic.c optional wii powerpc/wii/wii_fb.c optional wii powerpc/wii/wii_gpio.c optional wii wiigpio powerpc/wii/wii_ipc.c optional wii Index: stable/10/sys/dev/ofw/ofw_cpu.c =================================================================== --- stable/10/sys/dev/ofw/ofw_cpu.c (nonexistent) +++ stable/10/sys/dev/ofw/ofw_cpu.c (revision 278608) @@ -0,0 +1,214 @@ +/*- + * Copyright (C) 2009 Nathan Whitehorn + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY Benno Rice ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +static int ofw_cpulist_probe(device_t); +static int ofw_cpulist_attach(device_t); +static const struct ofw_bus_devinfo *ofw_cpulist_get_devinfo(device_t dev, + device_t child); + +static MALLOC_DEFINE(M_OFWCPU, "ofwcpu", "OFW CPU device information"); + +static device_method_t ofw_cpulist_methods[] = { + /* Device interface */ + DEVMETHOD(device_probe, ofw_cpulist_probe), + DEVMETHOD(device_attach, ofw_cpulist_attach), + + /* Bus interface */ + DEVMETHOD(bus_add_child, bus_generic_add_child), + DEVMETHOD(bus_child_pnpinfo_str, ofw_bus_gen_child_pnpinfo_str), + + /* ofw_bus interface */ + DEVMETHOD(ofw_bus_get_devinfo, ofw_cpulist_get_devinfo), + DEVMETHOD(ofw_bus_get_compat, ofw_bus_gen_get_compat), + DEVMETHOD(ofw_bus_get_model, ofw_bus_gen_get_model), + DEVMETHOD(ofw_bus_get_name, ofw_bus_gen_get_name), + DEVMETHOD(ofw_bus_get_node, ofw_bus_gen_get_node), + DEVMETHOD(ofw_bus_get_type, ofw_bus_gen_get_type), + + DEVMETHOD_END +}; + +static driver_t ofw_cpulist_driver = { + "cpulist", + ofw_cpulist_methods, + 0 +}; + +static devclass_t ofw_cpulist_devclass; + +DRIVER_MODULE(ofw_cpulist, ofwbus, ofw_cpulist_driver, ofw_cpulist_devclass, + 0, 0); + +static int +ofw_cpulist_probe(device_t dev) +{ + const char *name; + + name = ofw_bus_get_name(dev); + + if (name == NULL || strcmp(name, "cpus") != 0) + return (ENXIO); + + device_set_desc(dev, "Open Firmware CPU Group"); + + return (0); +} + +static int +ofw_cpulist_attach(device_t dev) +{ + phandle_t root, child; + device_t cdev; + struct ofw_bus_devinfo *dinfo; + + root = ofw_bus_get_node(dev); + + for (child = OF_child(root); child != 0; child = OF_peer(child)) { + dinfo = malloc(sizeof(*dinfo), M_OFWCPU, M_WAITOK | M_ZERO); + + if (ofw_bus_gen_setup_devinfo(dinfo, child) != 0) { + free(dinfo, M_OFWCPU); + continue; + } + cdev = device_add_child(dev, NULL, -1); + if (cdev == NULL) { + device_printf(dev, "<%s>: device_add_child failed\n", + dinfo->obd_name); + ofw_bus_gen_destroy_devinfo(dinfo); + free(dinfo, M_OFWCPU); + continue; + } + device_set_ivars(cdev, dinfo); + } + + return (bus_generic_attach(dev)); +} + +static const struct ofw_bus_devinfo * +ofw_cpulist_get_devinfo(device_t dev, device_t child) +{ + return (device_get_ivars(child)); +} + +static int ofw_cpu_probe(device_t); +static int ofw_cpu_attach(device_t); +static int ofw_cpu_read_ivar(device_t dev, device_t child, int index, + uintptr_t *result); + +struct ofw_cpu_softc { + struct pcpu *sc_cpu_pcpu; + uint32_t sc_nominal_mhz; +}; + +static device_method_t ofw_cpu_methods[] = { + /* Device interface */ + DEVMETHOD(device_probe, ofw_cpu_probe), + DEVMETHOD(device_attach, ofw_cpu_attach), + + /* Bus interface */ + DEVMETHOD(bus_add_child, bus_generic_add_child), + DEVMETHOD(bus_read_ivar, ofw_cpu_read_ivar), + DEVMETHOD(bus_setup_intr, bus_generic_setup_intr), + DEVMETHOD(bus_teardown_intr, bus_generic_teardown_intr), + DEVMETHOD(bus_alloc_resource, bus_generic_alloc_resource), + DEVMETHOD(bus_release_resource, bus_generic_release_resource), + DEVMETHOD(bus_activate_resource,bus_generic_activate_resource), + + DEVMETHOD_END +}; + +static driver_t ofw_cpu_driver = { + "cpu", + ofw_cpu_methods, + sizeof(struct ofw_cpu_softc) +}; + +static devclass_t ofw_cpu_devclass; + +DRIVER_MODULE(ofw_cpu, cpulist, ofw_cpu_driver, ofw_cpu_devclass, 0, 0); + +static int +ofw_cpu_probe(device_t dev) +{ + const char *type = ofw_bus_get_type(dev); + + if (strcmp(type, "cpu") != 0) + return (ENXIO); + + device_set_desc(dev, "Open Firmware CPU"); + return (0); +} + +static int +ofw_cpu_attach(device_t dev) +{ + struct ofw_cpu_softc *sc; + uint32_t cell; + + sc = device_get_softc(dev); + OF_getprop(ofw_bus_get_node(dev), "reg", &cell, sizeof(cell)); + sc->sc_cpu_pcpu = pcpu_find(cell); + OF_getprop(ofw_bus_get_node(dev), "clock-frequency", &cell, sizeof(cell)); + sc->sc_nominal_mhz = cell / 1000000; /* convert to MHz */ + + bus_generic_probe(dev); + return (bus_generic_attach(dev)); +} + +static int +ofw_cpu_read_ivar(device_t dev, device_t child, int index, uintptr_t *result) +{ + struct ofw_cpu_softc *sc; + + sc = device_get_softc(dev); + + switch (index) { + case CPU_IVAR_PCPU: + *result = (uintptr_t)sc->sc_cpu_pcpu; + return (0); + case CPU_IVAR_NOMINAL_MHZ: + *result = (uintptr_t)sc->sc_nominal_mhz; + return (0); + } + + return (ENOENT); +} + Property changes on: stable/10/sys/dev/ofw/ofw_cpu.c ___________________________________________________________________ Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Index: stable/10/sys/powerpc/ofw/ofw_cpu.c =================================================================== --- stable/10/sys/powerpc/ofw/ofw_cpu.c (revision 278607) +++ stable/10/sys/powerpc/ofw/ofw_cpu.c (nonexistent) @@ -1,214 +0,0 @@ -/*- - * Copyright (C) 2009 Nathan Whitehorn - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY Benno Rice ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include -__FBSDID("$FreeBSD$"); - -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -static int ofw_cpulist_probe(device_t); -static int ofw_cpulist_attach(device_t); -static const struct ofw_bus_devinfo *ofw_cpulist_get_devinfo(device_t dev, - device_t child); - -static MALLOC_DEFINE(M_OFWCPU, "ofwcpu", "OFW CPU device information"); - -static device_method_t ofw_cpulist_methods[] = { - /* Device interface */ - DEVMETHOD(device_probe, ofw_cpulist_probe), - DEVMETHOD(device_attach, ofw_cpulist_attach), - - /* Bus interface */ - DEVMETHOD(bus_add_child, bus_generic_add_child), - DEVMETHOD(bus_child_pnpinfo_str, ofw_bus_gen_child_pnpinfo_str), - - /* ofw_bus interface */ - DEVMETHOD(ofw_bus_get_devinfo, ofw_cpulist_get_devinfo), - DEVMETHOD(ofw_bus_get_compat, ofw_bus_gen_get_compat), - DEVMETHOD(ofw_bus_get_model, ofw_bus_gen_get_model), - DEVMETHOD(ofw_bus_get_name, ofw_bus_gen_get_name), - DEVMETHOD(ofw_bus_get_node, ofw_bus_gen_get_node), - DEVMETHOD(ofw_bus_get_type, ofw_bus_gen_get_type), - - DEVMETHOD_END -}; - -static driver_t ofw_cpulist_driver = { - "cpulist", - ofw_cpulist_methods, - 0 -}; - -static devclass_t ofw_cpulist_devclass; - -DRIVER_MODULE(ofw_cpulist, ofwbus, ofw_cpulist_driver, ofw_cpulist_devclass, - 0, 0); - -static int -ofw_cpulist_probe(device_t dev) -{ - const char *name; - - name = ofw_bus_get_name(dev); - - if (name == NULL || strcmp(name, "cpus") != 0) - return (ENXIO); - - device_set_desc(dev, "Open Firmware CPU Group"); - - return (0); -} - -static int -ofw_cpulist_attach(device_t dev) -{ - phandle_t root, child; - device_t cdev; - struct ofw_bus_devinfo *dinfo; - - root = ofw_bus_get_node(dev); - - for (child = OF_child(root); child != 0; child = OF_peer(child)) { - dinfo = malloc(sizeof(*dinfo), M_OFWCPU, M_WAITOK | M_ZERO); - - if (ofw_bus_gen_setup_devinfo(dinfo, child) != 0) { - free(dinfo, M_OFWCPU); - continue; - } - cdev = device_add_child(dev, NULL, -1); - if (cdev == NULL) { - device_printf(dev, "<%s>: device_add_child failed\n", - dinfo->obd_name); - ofw_bus_gen_destroy_devinfo(dinfo); - free(dinfo, M_OFWCPU); - continue; - } - device_set_ivars(cdev, dinfo); - } - - return (bus_generic_attach(dev)); -} - -static const struct ofw_bus_devinfo * -ofw_cpulist_get_devinfo(device_t dev, device_t child) -{ - return (device_get_ivars(child)); -} - -static int ofw_cpu_probe(device_t); -static int ofw_cpu_attach(device_t); -static int ofw_cpu_read_ivar(device_t dev, device_t child, int index, - uintptr_t *result); - -struct ofw_cpu_softc { - struct pcpu *sc_cpu_pcpu; - uint32_t sc_nominal_mhz; -}; - -static device_method_t ofw_cpu_methods[] = { - /* Device interface */ - DEVMETHOD(device_probe, ofw_cpu_probe), - DEVMETHOD(device_attach, ofw_cpu_attach), - - /* Bus interface */ - DEVMETHOD(bus_add_child, bus_generic_add_child), - DEVMETHOD(bus_read_ivar, ofw_cpu_read_ivar), - DEVMETHOD(bus_setup_intr, bus_generic_setup_intr), - DEVMETHOD(bus_teardown_intr, bus_generic_teardown_intr), - DEVMETHOD(bus_alloc_resource, bus_generic_alloc_resource), - DEVMETHOD(bus_release_resource, bus_generic_release_resource), - DEVMETHOD(bus_activate_resource,bus_generic_activate_resource), - - DEVMETHOD_END -}; - -static driver_t ofw_cpu_driver = { - "cpu", - ofw_cpu_methods, - sizeof(struct ofw_cpu_softc) -}; - -static devclass_t ofw_cpu_devclass; - -DRIVER_MODULE(ofw_cpu, cpulist, ofw_cpu_driver, ofw_cpu_devclass, 0, 0); - -static int -ofw_cpu_probe(device_t dev) -{ - const char *type = ofw_bus_get_type(dev); - - if (strcmp(type, "cpu") != 0) - return (ENXIO); - - device_set_desc(dev, "Open Firmware CPU"); - return (0); -} - -static int -ofw_cpu_attach(device_t dev) -{ - struct ofw_cpu_softc *sc; - uint32_t cell; - - sc = device_get_softc(dev); - OF_getprop(ofw_bus_get_node(dev), "reg", &cell, sizeof(cell)); - sc->sc_cpu_pcpu = pcpu_find(cell); - OF_getprop(ofw_bus_get_node(dev), "clock-frequency", &cell, sizeof(cell)); - sc->sc_nominal_mhz = cell / 1000000; /* convert to MHz */ - - bus_generic_probe(dev); - return (bus_generic_attach(dev)); -} - -static int -ofw_cpu_read_ivar(device_t dev, device_t child, int index, uintptr_t *result) -{ - struct ofw_cpu_softc *sc; - - sc = device_get_softc(dev); - - switch (index) { - case CPU_IVAR_PCPU: - *result = (uintptr_t)sc->sc_cpu_pcpu; - return (0); - case CPU_IVAR_NOMINAL_MHZ: - *result = (uintptr_t)sc->sc_nominal_mhz; - return (0); - } - - return (ENOENT); -} - Property changes on: stable/10/sys/powerpc/ofw/ofw_cpu.c ___________________________________________________________________ Deleted: svn:keywords ## -1 +0,0 ## -FreeBSD=%H \ No newline at end of property Index: stable/10 =================================================================== --- stable/10 (revision 278607) +++ stable/10 (revision 278608) Property changes on: stable/10 ___________________________________________________________________ Modified: svn:mergeinfo ## -0,0 +0,1 ## Merged /head:r275779,275963,276101,276161,276297