static void rpi_get_board_rev(void) { int ret; char *name; BCM2835_MBOX_STACK_ALIGN(struct msg_get_board_rev, msg); BCM2835_MBOX_INIT_HDR(msg); BCM2835_MBOX_INIT_TAG(&msg->get_board_rev, GET_BOARD_REV); ret = bcm2835_mbox_call_prop(BCM2835_MBOX_PROP_CHAN, &msg->hdr); if (ret) { printf("bcm2835: Could not query board revision\n"); /* Ignore error; not critical */ return; } /* Comments from u-boot: * For details of old-vs-new scheme, see: * https://github.com/pimoroni/RPi.version/blob/master/RPi/version.py * http://www.raspberrypi.org/forums/viewtopic.php?f=63&t=99293&p=690282 * (a few posts down) * * For the RPi 1, bit 24 is the "warranty bit", so we mask off just the * lower byte to use as the board rev: * http://www.raspberrypi.org/forums/viewtopic.php?f=63&t=98367&start=250 * http://www.raspberrypi.org/forums/viewtopic.php?f=31&t=20594 */ rpi_board_rev = msg->get_board_rev.body.resp.rev; if (rpi_board_rev & 0x800000) rpi_board_rev = (rpi_board_rev >> 4) & 0xff; else
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_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_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_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 struct clk *rpi_register_firmware_clock(u32 clock_id, const char *name) { BCM2835_MBOX_STACK_ALIGN(struct msg_get_clock_rate, msg); int ret; BCM2835_MBOX_INIT_HDR(msg); BCM2835_MBOX_INIT_TAG(&msg->get_clock_rate, GET_CLOCK_RATE); msg->get_clock_rate.body.req.clock_id = clock_id; ret = bcm2835_mbox_call_prop(BCM2835_MBOX_PROP_CHAN, &msg->hdr); if (ret) return ERR_PTR(ret); return clk_fixed(name, msg->get_clock_rate.body.resp.rate_hz); }
static int rpi_get_arm_mem(u32 *size) { BCM2835_MBOX_STACK_ALIGN(struct msg_get_arm_mem, msg); int ret; BCM2835_MBOX_INIT_HDR(msg); BCM2835_MBOX_INIT_TAG(&msg->get_arm_mem, GET_ARM_MEMORY); ret = bcm2835_mbox_call_prop(BCM2835_MBOX_PROP_CHAN, &msg->hdr); if (ret) return ret; *size = msg->get_arm_mem.body.resp.mem_size; return 0; }
void rpi_set_usbethaddr(void) { BCM2835_MBOX_STACK_ALIGN(struct msg_get_mac_address, msg); int ret; BCM2835_MBOX_INIT_HDR(msg); BCM2835_MBOX_INIT_TAG(&msg->get_mac_address, GET_MAC_ADDRESS); ret = bcm2835_mbox_call_prop(BCM2835_MBOX_PROP_CHAN, &msg->hdr); if (ret) { printf("bcm2835: Could not query MAC address\n"); /* Ignore error; not critical */ return; } eth_register_ethaddr(0, msg->get_mac_address.body.resp.mac); }
static int rpi_register_clkdev(u32 clock_id, const char *name) { BCM2835_MBOX_STACK_ALIGN(struct msg_get_clock_rate, msg); struct clk *clk; int ret; BCM2835_MBOX_INIT_HDR(msg); BCM2835_MBOX_INIT_TAG(&msg->get_clock_rate, GET_CLOCK_RATE); msg->get_clock_rate.body.req.clock_id = clock_id; ret = bcm2835_mbox_call_prop(BCM2835_MBOX_PROP_CHAN, &msg->hdr); if (ret) return ret; clk = clk_fixed(name, msg->get_clock_rate.body.resp.rate_hz); if (IS_ERR(clk)) return PTR_ERR(clk); if (!clk_register_clkdev(clk, NULL, name)) return -ENODEV; return 0; }
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_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); }