diff options
Diffstat (limited to 'arch/arm/boards/raspberry-pi/rpi-common.c')
-rw-r--r-- | arch/arm/boards/raspberry-pi/rpi-common.c | 294 |
1 files changed, 294 insertions, 0 deletions
diff --git a/arch/arm/boards/raspberry-pi/rpi-common.c b/arch/arm/boards/raspberry-pi/rpi-common.c new file mode 100644 index 0000000000..0e17587a74 --- /dev/null +++ b/arch/arm/boards/raspberry-pi/rpi-common.c @@ -0,0 +1,294 @@ +/* + * Copyright (C) 2009 Carlo Caione <carlo@carlocaione.org> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#include <common.h> +#include <init.h> +#include <fs.h> +#include <linux/stat.h> +#include <linux/clk.h> +#include <linux/clkdev.h> +#include <envfs.h> +#include <malloc.h> +#include <gpio.h> +#include <net.h> +#include <led.h> +#include <asm/armlinux.h> +#include <generated/mach-types.h> + +#include <mach/core.h> +#include <mach/mbox.h> + +#include "rpi.h" + +struct msg_get_arm_mem { + struct bcm2835_mbox_hdr hdr; + struct bcm2835_mbox_tag_get_arm_mem get_arm_mem; + u32 end_tag; +}; + +struct msg_get_clock_rate { + struct bcm2835_mbox_hdr hdr; + struct bcm2835_mbox_tag_get_clock_rate get_clock_rate; + 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); + 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; +} + +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; +} + +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); +} + +struct gpio_led rpi_leds[] = { + { + .gpio = -EINVAL, + .led = { + .name = "ACT", + }, + }, { + .gpio = -EINVAL, + .led = { + .name = "PWR", + }, + }, +}; + +void rpi_add_led(void) +{ + int i; + struct gpio_led *l; + + for (i = 0; i < ARRAY_SIZE(rpi_leds); i++) { + l = &rpi_leds[i]; + + if (gpio_is_valid(l->gpio)) + led_gpio_register(l); + } + + l = &rpi_leds[0]; + if (gpio_is_valid(l->gpio)) + led_set_trigger(LED_TRIGGER_HEARTBEAT, &l->led); +} + +void rpi_b_plus_init(void) +{ + rpi_leds[0].gpio = 47; + rpi_leds[1].gpio = 35; + rpi_set_usbethaddr(); +} + +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; + } + + /* 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 + rpi_board_rev &= 0xff; + if (rpi_board_rev >= rpi_models_size) { + printf("RPI: Board rev %u outside known range\n", + rpi_board_rev); + goto unknown_rev; + } + + if (!rpi_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 %s", rpi_models[rpi_board_rev].name, + rpi_model_string); + barebox_set_model(name); + free(name); + + return; + +unknown_rev: + rpi_board_rev = 0; + name = asprintf("RaspberryPi %s", rpi_model_string); + barebox_set_model(name); + free(name); +} + +static void rpi_model_init(void) +{ + if (!rpi_models[rpi_board_rev].init) + return; + + rpi_models[rpi_board_rev].init(); + rpi_add_led(); +} + +static int rpi_mem_init(void) +{ + u32 size = 0; + int ret; + + ret = rpi_get_arm_mem(&size); + if (ret) + printf("could not query ARM memory size\n"); + + bcm2835_add_device_sdram(size); + + return ret; +} +mem_initcall(rpi_mem_init); + +static int rpi_console_init(void) +{ + rpi_get_board_rev(); + barebox_set_hostname("rpi"); + + bcm2835_register_uart(); + return 0; +} +console_initcall(rpi_console_init); + +static int rpi_clock_init(void) +{ + rpi_register_clkdev(BCM2835_MBOX_CLOCK_ID_EMMC, "bcm2835_mci0"); + return 0; +} +postconsole_initcall(rpi_clock_init); + +static int rpi_env_init(void) +{ + struct stat s; + const char *diskdev = "/dev/disk0.0"; + int ret; + + device_detect_by_name("mci0"); + + ret = stat(diskdev, &s); + if (ret) { + printf("no %s. using default env\n", diskdev); + return 0; + } + + mkdir("/boot", 0666); + ret = mount(diskdev, "fat", "/boot", NULL); + if (ret) { + printf("failed to mount %s\n", diskdev); + return 0; + } + + default_environment_path_set("/boot/barebox.env"); + + return 0; +} + +static int rpi_devices_init(void) +{ + rpi_model_init(); + bcm2835_register_mci(); + bcm2835_register_fb(); + armlinux_set_architecture(MACH_TYPE_BCM2708); + rpi_env_init(); + return 0; +} +late_initcall(rpi_devices_init); |