Example #1
0
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
Example #2
0
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);
}
Example #3
0
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);
}
Example #4
0
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);
}
Example #5
0
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);
}
Example #6
0
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);
}
Example #7
0
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;
}
Example #8
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);
}
Example #9
0
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;
}
Example #10
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);
}
Example #11
0
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);
}