diff --git a/arch/arm/boards/raspberry-pi/env/init/ps1 b/arch/arm/boards/raspberry-pi/env/init/ps1 new file mode 100644 index 0000000..f894846 --- /dev/null +++ b/arch/arm/boards/raspberry-pi/env/init/ps1 @@ -0,0 +1,7 @@ +#!/bin/sh + +if [ ${global.allow_color} = "true" ]; then + export PS1="\e[1;32mbarebox@\e[1;36m\h:\w\e[0m\n# " +else + export PS1="barebox@\h:\w\n# " +fi diff --git a/arch/arm/boards/raspberry-pi/rpi.c b/arch/arm/boards/raspberry-pi/rpi.c index 03a16d7..f9406d4 100644 --- a/arch/arm/boards/raspberry-pi/rpi.c +++ b/arch/arm/boards/raspberry-pi/rpi.c @@ -20,6 +20,10 @@ #include #include #include +#include +#include +#include +#include #include #include @@ -38,6 +42,18 @@ u32 end_tag; }; +struct msg_get_board_rev { + struct bcm2835_mbox_hdr hdr; + struct bcm2835_mbox_tag_get_board_rev get_board_rev; + u32 end_tag; +}; + +struct msg_get_mac_address { + struct bcm2835_mbox_hdr hdr; + struct bcm2835_mbox_tag_get_mac_address get_mac_address; + u32 end_tag; +}; + static int rpi_get_arm_mem(u32 *size) { BCM2835_MBOX_STACK_ALIGN(struct msg_get_arm_mem, msg); @@ -79,6 +95,150 @@ return 0; } +static 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 struct gpio_led leds[] = { + { + .gpio = -EINVAL, + .led = { + .name = "ACT", + }, + }, { + .gpio = -EINVAL, + .led = { + .name = "PWR", + }, + }, +}; + +static void rpi_add_led(void) +{ + int i; + struct gpio_led *l; + + for (i = 0; i < ARRAY_SIZE(leds); i++) { + l = &leds[i]; + + if (gpio_is_valid(l->gpio)) + led_gpio_register(l); + } + + l = &leds[0]; + if (gpio_is_valid(l->gpio)) + led_set_trigger(LED_TRIGGER_HEARTBEAT, &l->led); +} + +static void rpi_b_plus_init(void) +{ + leds[0].gpio = 47; + leds[1].gpio = 35; + rpi_set_usbethaddr(); +} + +static void rpi_b_init(void) +{ + leds[0].gpio = 16; + leds[0].active_low = 1; + rpi_set_usbethaddr(); +} + +#define RPI_MODEL(_id, _name, _init) \ + [_id] = { \ + .name = _name,\ + .init = _init,\ + } +/* See comments in mbox.h for data source */ +static const struct { + const char *name; + void (*init)(void); +} models[] = { + RPI_MODEL(0, "Unknown model", NULL), + RPI_MODEL(BCM2835_BOARD_REV_B_I2C0_2, "Model B (no P5)", rpi_b_init), + RPI_MODEL(BCM2835_BOARD_REV_B_I2C0_3, "Model B (no P5)", rpi_b_init), + RPI_MODEL(BCM2835_BOARD_REV_B_I2C1_4, "Model B", rpi_b_init), + RPI_MODEL(BCM2835_BOARD_REV_B_I2C1_5, "Model B", rpi_b_init), + RPI_MODEL(BCM2835_BOARD_REV_B_I2C1_6, "Model B", rpi_b_init), + RPI_MODEL(BCM2835_BOARD_REV_A_7, "Model A", NULL), + RPI_MODEL(BCM2835_BOARD_REV_A_8, "Model A", NULL), + RPI_MODEL(BCM2835_BOARD_REV_A_9, "Model A", NULL), + RPI_MODEL(BCM2835_BOARD_REV_B_REV2_d, "Model B rev2", rpi_b_init), + RPI_MODEL(BCM2835_BOARD_REV_B_REV2_e, "Model B rev2", rpi_b_init), + RPI_MODEL(BCM2835_BOARD_REV_B_REV2_f, "Model B rev2", rpi_b_init), + RPI_MODEL(BCM2835_BOARD_REV_B_PLUS, "Model B+", rpi_b_plus_init), + RPI_MODEL(BCM2835_BOARD_REV_CM, "Compute Module", NULL), + RPI_MODEL(BCM2835_BOARD_REV_A_PLUS, "Model A+", NULL), +}; + +static int rpi_board_rev = 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; + } + + rpi_board_rev = msg->get_board_rev.body.resp.rev; + if (rpi_board_rev >= ARRAY_SIZE(models)) { + printf("RPI: Board rev %u outside known range\n", + rpi_board_rev); + goto unknown_rev; + } + + if (!models[rpi_board_rev].name) { + printf("RPI: Board rev %u unknown\n", rpi_board_rev); + goto unknown_rev; + } + + if (!rpi_board_rev) + goto unknown_rev; + + name = asprintf("RaspberryPi %s (BCM2835/ARM1176JZF-S)", + models[rpi_board_rev].name); + barebox_set_model(name); + free(name); + + return; + +unknown_rev: + rpi_board_rev = 0; + barebox_set_model("RaspberryPi (BCM2835/ARM1176JZF-S)"); +} + +static void rpi_model_init(void) +{ + if (!models[rpi_board_rev].init) + return; + + models[rpi_board_rev].init(); + rpi_add_led(); +} + static int rpi_mem_init(void) { u32 size = 0; @@ -96,7 +256,7 @@ static int rpi_console_init(void) { - barebox_set_model("RaspberryPi (BCM2835/ARM1176JZF-S)"); + rpi_get_board_rev(); barebox_set_hostname("rpi"); bcm2835_register_uart(); @@ -139,6 +299,7 @@ static int rpi_devices_init(void) { + rpi_model_init(); bcm2835_register_mci(); bcm2835_register_fb(); armlinux_set_architecture(MACH_TYPE_BCM2708); diff --git a/arch/arm/mach-bcm2835/core.c b/arch/arm/mach-bcm2835/core.c index 7f3d7e7..5d08012 100644 --- a/arch/arm/mach-bcm2835/core.c +++ b/arch/arm/mach-bcm2835/core.c @@ -72,7 +72,7 @@ } #define RESET_TIMEOUT 10 -void __noreturn reset_cpu (unsigned long addr) +void __noreturn reset_cpu(unsigned long addr) { uint32_t rstc; diff --git a/arch/arm/mach-bcm2835/include/mach/mbox.h b/arch/arm/mach-bcm2835/include/mach/mbox.h index fb8a9bf..4c3fd77 100644 --- a/arch/arm/mach-bcm2835/include/mach/mbox.h +++ b/arch/arm/mach-bcm2835/include/mach/mbox.h @@ -124,6 +124,54 @@ * }; */ +#define BCM2835_MBOX_TAG_GET_BOARD_REV 0x00010002 + +/* + * 0x2..0xf from: + * http://raspberryalphaomega.org.uk/2013/02/06/automatic-raspberry-pi-board-revision-detection-model-a-b1-and-b2/ + * http://www.raspberrypi.org/forums/viewtopic.php?f=63&t=32733 + * 0x10, 0x11 from swarren's testing + */ +#define BCM2835_BOARD_REV_B_I2C0_2 0x2 +#define BCM2835_BOARD_REV_B_I2C0_3 0x3 +#define BCM2835_BOARD_REV_B_I2C1_4 0x4 +#define BCM2835_BOARD_REV_B_I2C1_5 0x5 +#define BCM2835_BOARD_REV_B_I2C1_6 0x6 +#define BCM2835_BOARD_REV_A_7 0x7 +#define BCM2835_BOARD_REV_A_8 0x8 +#define BCM2835_BOARD_REV_A_9 0x9 +#define BCM2835_BOARD_REV_B_REV2_d 0xd +#define BCM2835_BOARD_REV_B_REV2_e 0xe +#define BCM2835_BOARD_REV_B_REV2_f 0xf +#define BCM2835_BOARD_REV_B_PLUS 0x10 +#define BCM2835_BOARD_REV_CM 0x11 +#define BCM2835_BOARD_REV_A_PLUS 0x12 + +struct bcm2835_mbox_tag_get_board_rev { + struct bcm2835_mbox_tag_hdr tag_hdr; + union { + struct { + } req; + struct { + u32 rev; + } resp; + } body; +}; + +#define BCM2835_MBOX_TAG_GET_MAC_ADDRESS 0x00010003 + +struct bcm2835_mbox_tag_get_mac_address { + struct bcm2835_mbox_tag_hdr tag_hdr; + union { + struct { + } req; + struct { + u8 mac[6]; + u8 pad[2]; + } resp; + } body; +}; + #define BCM2835_MBOX_TAG_GET_ARM_MEMORY 0x00010005 struct bcm2835_mbox_tag_get_arm_mem { @@ -138,6 +186,55 @@ } body; }; +#define BCM2835_MBOX_POWER_DEVID_SDHCI 0 +#define BCM2835_MBOX_POWER_DEVID_UART0 1 +#define BCM2835_MBOX_POWER_DEVID_UART1 2 +#define BCM2835_MBOX_POWER_DEVID_USB_HCD 3 +#define BCM2835_MBOX_POWER_DEVID_I2C0 4 +#define BCM2835_MBOX_POWER_DEVID_I2C1 5 +#define BCM2835_MBOX_POWER_DEVID_I2C2 6 +#define BCM2835_MBOX_POWER_DEVID_SPI 7 +#define BCM2835_MBOX_POWER_DEVID_CCP2TX 8 + +#define BCM2835_MBOX_POWER_STATE_RESP_ON (1 << 0) +/* Device doesn't exist */ +#define BCM2835_MBOX_POWER_STATE_RESP_NODEV (1 << 1) + +#define BCM2835_MBOX_TAG_GET_POWER_STATE 0x00020001 + +struct bcm2835_mbox_tag_get_power_state { + struct bcm2835_mbox_tag_hdr tag_hdr; + union { + struct { + u32 device_id; + } req; + struct { + u32 device_id; + u32 state; + } resp; + } body; +}; + +#define BCM2835_MBOX_TAG_SET_POWER_STATE 0x00028001 + +#define BCM2835_MBOX_SET_POWER_STATE_REQ_OFF (0 << 0) +#define BCM2835_MBOX_SET_POWER_STATE_REQ_ON (1 << 0) +#define BCM2835_MBOX_SET_POWER_STATE_REQ_WAIT (1 << 1) + +struct bcm2835_mbox_tag_set_power_state { + struct bcm2835_mbox_tag_hdr tag_hdr; + union { + struct { + u32 device_id; + u32 state; + } req; + struct { + u32 device_id; + u32 state; + } resp; + } body; +}; + #define BCM2835_MBOX_TAG_GET_CLOCK_RATE 0x00030002 #define BCM2835_MBOX_CLOCK_ID_EMMC 1 diff --git a/arch/arm/mach-bcm2835/mbox.c b/arch/arm/mach-bcm2835/mbox.c index 2bca567..1a80771 100644 --- a/arch/arm/mach-bcm2835/mbox.c +++ b/arch/arm/mach-bcm2835/mbox.c @@ -13,7 +13,7 @@ #include -#define TIMEOUT (MSECOND * 100) /* 100mS */ +#define TIMEOUT (MSECOND * 1000) static int bcm2835_mbox_call_raw(u32 chan, struct bcm2835_mbox_hdr *buffer, u32 *recv) diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig index 493b18a..05c3f48 100644 --- a/drivers/regulator/Kconfig +++ b/drivers/regulator/Kconfig @@ -1,5 +1,4 @@ menuconfig REGULATOR - depends on OFDEVICE bool "voltage regulator support" if REGULATOR @@ -7,8 +6,14 @@ config REGULATOR_FIXED bool "fixed/gpio regulator" depends on GENERIC_GPIO + depends on OFDEVICE help This enables a simple fixed regulator. It is used for regulators which are not software controllable or controllable via gpio. +config REGULATOR_BCM2835 + bool + depends on ARCH_BCM2835 + default y + endif diff --git a/drivers/regulator/Makefile b/drivers/regulator/Makefile index 65e65d8..d663c16 100644 --- a/drivers/regulator/Makefile +++ b/drivers/regulator/Makefile @@ -1,2 +1,3 @@ obj-$(CONFIG_REGULATOR) += core.o obj-$(CONFIG_REGULATOR_FIXED) += fixed.o +obj-$(CONFIG_REGULATOR_BCM2835) += bcm2835.o diff --git a/drivers/regulator/bcm2835.c b/drivers/regulator/bcm2835.c new file mode 100644 index 0000000..0ada05d --- /dev/null +++ b/drivers/regulator/bcm2835.c @@ -0,0 +1,149 @@ +/* + * bcm2835 regulator support + * + * Copyright (c) 2015 Jean-Christophe PLAGNIOL-VILLARD + * + * GPLv2 Only + */ +#include +#include +#include +#include + +#include + +#define REG_DEV(_id, _name) \ + { \ + .id = _id, \ + .devname = _name,\ + } + +static struct regulator_bcm2835 { + int id; + char *devname; + + struct device_d *dev; + struct regulator_dev rdev; +} regs[] = { + REG_DEV(BCM2835_MBOX_POWER_DEVID_SDHCI, "bcm2835_mci0"), + REG_DEV(BCM2835_MBOX_POWER_DEVID_UART0, "uart0-pl0110"), + REG_DEV(BCM2835_MBOX_POWER_DEVID_UART1, "uart0-pl0111"), + REG_DEV(BCM2835_MBOX_POWER_DEVID_USB_HCD, "bcm2835_usb"), + REG_DEV(BCM2835_MBOX_POWER_DEVID_I2C0, "bcm2835_i2c0"), + REG_DEV(BCM2835_MBOX_POWER_DEVID_I2C1, "bcm2835_i2c1"), + REG_DEV(BCM2835_MBOX_POWER_DEVID_I2C2, "bcm2835_i2c2"), + REG_DEV(BCM2835_MBOX_POWER_DEVID_SPI, "bcm2835_spi"), + REG_DEV(BCM2835_MBOX_POWER_DEVID_CCP2TX, "bcm2835_ccp2tx"), +}; + +struct msg_set_power_state { + struct bcm2835_mbox_hdr hdr; + struct bcm2835_mbox_tag_set_power_state set_power_state; + u32 end_tag; +}; + +static int regulator_bcm2835_set(struct regulator_bcm2835 *rb, int state) +{ + BCM2835_MBOX_STACK_ALIGN(struct msg_set_power_state, msg_pwr); + int ret; + + BCM2835_MBOX_INIT_HDR(msg_pwr); + BCM2835_MBOX_INIT_TAG(&msg_pwr->set_power_state, + SET_POWER_STATE); + msg_pwr->set_power_state.body.req.device_id = rb->id; + msg_pwr->set_power_state.body.req.state = + state | + BCM2835_MBOX_SET_POWER_STATE_REQ_WAIT; + + ret = bcm2835_mbox_call_prop(BCM2835_MBOX_PROP_CHAN, + &msg_pwr->hdr); + if (ret) { + dev_err(rb->dev ,"bcm2835: Could not set module %u power state\n", + rb->id); + return ret; + } + + return 0; +} + +static int regulator_bcm2835_enable(struct regulator_dev *rdev) +{ + struct regulator_bcm2835 *rb = container_of(rdev, struct regulator_bcm2835, rdev); + + return regulator_bcm2835_set(rb, BCM2835_MBOX_SET_POWER_STATE_REQ_ON); +} + +static int regulator_bcm2835_disable(struct regulator_dev *rdev) +{ + struct regulator_bcm2835 *rb = container_of(rdev, struct regulator_bcm2835, rdev); + + return regulator_bcm2835_set(rb, BCM2835_MBOX_SET_POWER_STATE_REQ_OFF); +} + +struct msg_get_power_state { + struct bcm2835_mbox_hdr hdr; + struct bcm2835_mbox_tag_get_power_state get_power_state; + u32 end_tag; +}; + +static int regulator_bcm2835_is_enabled(struct regulator_dev *rdev) +{ + struct regulator_bcm2835 *rb = container_of(rdev, struct regulator_bcm2835, rdev); + BCM2835_MBOX_STACK_ALIGN(struct msg_get_power_state, msg_pwr); + int ret; + + BCM2835_MBOX_INIT_HDR(msg_pwr); + BCM2835_MBOX_INIT_TAG(&msg_pwr->get_power_state, + GET_POWER_STATE); + msg_pwr->get_power_state.body.req.device_id = rb->id; + + ret = bcm2835_mbox_call_prop(BCM2835_MBOX_PROP_CHAN, + &msg_pwr->hdr); + if (ret) { + dev_err(rb->dev ,"bcm2835: Could not get module %u power state\n", + rb->id); + return ret; + } + + return msg_pwr->get_power_state.body.resp.state; +} + +static struct regulator_ops bcm2835_ops = { + .enable = regulator_bcm2835_enable, + .disable = regulator_bcm2835_disable, + .is_enabled = regulator_bcm2835_is_enabled, +}; + +static int regulator_bcm2835_probe(struct device_d *dev) +{ + struct regulator_bcm2835 *rb; + int ret, i; + + for (i = 0; i < ARRAY_SIZE(regs); i++) { + rb = ®s[i]; + + rb->rdev.ops = &bcm2835_ops; + rb->dev = dev; + + ret = dev_regulator_register(&rb->rdev, rb->devname, NULL); + if (ret) + return ret; + } + + return 0; +} + +static struct driver_d regulator_bcm2835_driver = { + .name = "regulator-bcm2835", + .probe = regulator_bcm2835_probe, +}; +postcore_platform_driver(regulator_bcm2835_driver); + +static int regulator_bcm2835_init(void) +{ + add_generic_device("regulator-bcm2835", DEVICE_ID_SINGLE, NULL, + 0, 0, 0, NULL); + + return 0; +} +postcore_initcall(regulator_bcm2835_init); diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c index 2808c27..a3c9e41 100644 --- a/drivers/regulator/core.c +++ b/drivers/regulator/core.c @@ -33,6 +33,7 @@ int min_uv; int max_uv; char *name; + const char *supply; struct list_head consumer_list; }; @@ -42,6 +43,25 @@ struct device_d *dev; }; +static struct regulator_internal * __regulator_register(struct regulator_dev *rd, const char *name) +{ + struct regulator_internal *ri; + + ri = xzalloc(sizeof(*ri)); + ri->rdev = rd; + + INIT_LIST_HEAD(&ri->consumer_list); + + list_add_tail(&ri->list, ®ulator_list); + + if (name) + ri->name = xstrdup(name); + + return ri; +} + + +#ifdef CONFIG_OFDEVICE /* * of_regulator_register - register a regulator corresponding to a device_node * @rd: the regulator device providing the ops @@ -54,18 +74,10 @@ struct regulator_internal *ri; const char *name; - ri = xzalloc(sizeof(*ri)); - ri->rdev = rd; - ri->node = node; - - INIT_LIST_HEAD(&ri->consumer_list); - - list_add_tail(&ri->list, ®ulator_list); - name = of_get_property(node, "regulator-name", NULL); - if (name) - ri->name = xstrdup(name); + ri = __regulator_register(rd, name); + ri->node = node; of_property_read_u32(node, "regulator-enable-ramp-delay", &ri->enable_time_us); @@ -127,6 +139,55 @@ return ri; } +#else +static struct regulator_internal *of_regulator_get(struct device_d *dev, const char *supply) +{ + return NULL; +} +#endif + +int dev_regulator_register(struct regulator_dev *rd, const char * name, const char* supply) +{ + struct regulator_internal *ri; + + ri = __regulator_register(rd, name); + + ri->supply = supply; + + return 0; +} + +static struct regulator_internal *dev_regulator_get(struct device_d *dev, const char *supply) +{ + struct regulator_internal *ri; + struct regulator_internal *ret = NULL; + int match, best = 0; + const char *dev_id = dev ? dev_name(dev) : NULL; + + list_for_each_entry(ri, ®ulator_list, list) { + match = 0; + if (ri->name) { + if (!dev_id || strcmp(ri->name, dev_id)) + continue; + match += 2; + } + if (ri->supply) { + if (!supply || strcmp(ri->supply, supply)) + continue; + match += 1; + } + + if (match > best) { + ret = ri; + if (match != 3) + best = match; + else + break; + } + } + + return ret; +} /* * regulator_get - get the supply for a device. @@ -140,15 +201,20 @@ */ struct regulator *regulator_get(struct device_d *dev, const char *supply) { - struct regulator_internal *ri; + struct regulator_internal *ri = NULL; struct regulator *r; - if (!dev->device_node) - return NULL; + if (dev->device_node) { + ri = of_regulator_get(dev, supply); + if (IS_ERR(ri)) + return ERR_CAST(ri); + } - ri = of_regulator_get(dev, supply); - if (IS_ERR(ri)) - return ERR_CAST(ri); + if (!ri) { + ri = dev_regulator_get(dev, supply); + if (IS_ERR(ri)) + return ERR_CAST(ri); + } if (!ri) return NULL; diff --git a/drivers/serial/amba-pl011.c b/drivers/serial/amba-pl011.c index fc7723e..4c4067d 100644 --- a/drivers/serial/amba-pl011.c +++ b/drivers/serial/amba-pl011.c @@ -28,6 +28,7 @@ #include #include #include +#include #include #include #include @@ -181,6 +182,16 @@ { struct amba_uart_port *uart; struct console_device *cdev; + struct regulator *r; + + r = regulator_get(&dev->dev, NULL); + if (r) { + int ret; + + ret = regulator_enable(r); + if (ret) + return ret; + } uart = xzalloc(sizeof(struct amba_uart_port)); uart->clk = clk_get(&dev->dev, NULL); diff --git a/include/driver.h b/include/driver.h index 46aae4f..76fd4b1 100644 --- a/include/driver.h +++ b/include/driver.h @@ -409,6 +409,8 @@ } \ level##_initcall(drv##_register) +#define postcore_platform_driver(drv) \ + register_driver_macro(postcore,platform,drv) #define coredevice_platform_driver(drv) \ register_driver_macro(coredevice,platform,drv) #define device_platform_driver(drv) \ diff --git a/include/regulator.h b/include/regulator.h index 26a5e56..a43d3df 100644 --- a/include/regulator.h +++ b/include/regulator.h @@ -15,7 +15,17 @@ int (*is_enabled) (struct regulator_dev *); }; +#ifdef CONFIG_OFDEVICE int of_regulator_register(struct regulator_dev *rd, struct device_node *node); +#else +static inline int of_regulator_register(struct regulator_dev *rd, + struct device_node *node) +{ + return -ENOSYS; +} +#endif +int dev_regulator_register(struct regulator_dev *rd, const char * name, + const char* supply); void regulators_print(void);