From b95a2bbbcae5423e5404a7b3c8dd1685e1786f13 Mon Sep 17 00:00:00 2001 From: Maxime Bizon Date: Wed, 17 Sep 2008 15:55:36 +0200 Subject: [PATCH] [MIPS] BCM63XX: Add preliminary board support. Signed-off-by: Maxime Bizon --- arch/mips/bcm63xx/Kconfig | 2 + arch/mips/bcm63xx/Makefile | 2 + arch/mips/bcm63xx/boards/Kconfig | 10 + arch/mips/bcm63xx/boards/Makefile | 1 + arch/mips/bcm63xx/boards/board_bcm963xx.c | 322 ++++++++++++++++++++++++ arch/mips/bcm63xx/prom.c | 4 + arch/mips/bcm63xx/setup.c | 16 +- include/asm-mips/mach-bcm63xx/bcm63xx_board.h | 12 + include/asm-mips/mach-bcm63xx/board_bcm963xx.h | 50 ++++ 9 files changed, 417 insertions(+), 2 deletions(-) create mode 100644 arch/mips/bcm63xx/boards/Kconfig create mode 100644 arch/mips/bcm63xx/boards/Makefile create mode 100644 arch/mips/bcm63xx/boards/board_bcm963xx.c create mode 100644 include/asm-mips/mach-bcm63xx/bcm63xx_board.h create mode 100644 include/asm-mips/mach-bcm63xx/board_bcm963xx.h diff --git a/arch/mips/bcm63xx/Kconfig b/arch/mips/bcm63xx/Kconfig index be120f7..8c192e7 100644 --- a/arch/mips/bcm63xx/Kconfig +++ b/arch/mips/bcm63xx/Kconfig @@ -17,3 +17,5 @@ config BCM63XX_CPU_6358 select USB_ARCH_HAS_EHCI select USB_EHCI_BIG_ENDIAN_MMIO endmenu + +source "arch/mips/bcm63xx/boards/Kconfig" diff --git a/arch/mips/bcm63xx/Makefile b/arch/mips/bcm63xx/Makefile index 5358093..10462ae 100644 --- a/arch/mips/bcm63xx/Makefile +++ b/arch/mips/bcm63xx/Makefile @@ -5,3 +5,5 @@ obj-y += dev-usb-ohci.o obj-y += dev-usb-ehci.o obj-y += dev-enet.o obj-$(CONFIG_EARLY_PRINTK) += early_printk.o + +obj-y += boards/ diff --git a/arch/mips/bcm63xx/boards/Kconfig b/arch/mips/bcm63xx/boards/Kconfig new file mode 100644 index 0000000..da5eeaa --- /dev/null +++ b/arch/mips/bcm63xx/boards/Kconfig @@ -0,0 +1,10 @@ +choice + prompt "Board support" + depends on BCM63XX + default BOARD_BCM963XX + +config BOARD_BCM963XX + bool "Generic Broadcom 963xx boards" + help + +endchoice diff --git a/arch/mips/bcm63xx/boards/Makefile b/arch/mips/bcm63xx/boards/Makefile new file mode 100644 index 0000000..af07c1a --- /dev/null +++ b/arch/mips/bcm63xx/boards/Makefile @@ -0,0 +1 @@ +obj-$(CONFIG_BOARD_BCM963XX) += board_bcm963xx.o diff --git a/arch/mips/bcm63xx/boards/board_bcm963xx.c b/arch/mips/bcm63xx/boards/board_bcm963xx.c new file mode 100644 index 0000000..de52a2a --- /dev/null +++ b/arch/mips/bcm63xx/boards/board_bcm963xx.c @@ -0,0 +1,322 @@ +/* + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright (C) 2008 Maxime Bizon + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define PFX "board_bcm963xx: " + +static struct bcm963xx_nvram nvram; +static unsigned int mac_addr_used = 0; +static struct board_info board; + +/* + * known 6348 boards + */ +#ifdef CONFIG_BCM63XX_CPU_6348 +static struct board_info __initdata board_96348r = { + .name = "96348R", + .expected_cpu_id = 0x6348, + + .has_enet0 = 1, + .has_pci = 1, + + .enet0 = { + .has_phy = 1, + .use_internal_phy = 1, + }, +}; + +static struct board_info __initdata board_96348gw = { + .name = "96348GW", + .expected_cpu_id = 0x6348, + + .has_enet0 = 1, + .has_pci = 1, + + .enet0 = { + .has_phy = 1, + .use_internal_phy = 1, + }, +}; +#endif + +/* + * known 6358 boards + */ +#ifdef CONFIG_BCM63XX_CPU_6358 +static struct board_info __initdata board_96358vw2 = { + .name = "96358VW2", + .expected_cpu_id = 0x6358, + + .has_enet0 = 1, + .has_enet1 = 1, + .has_pci = 1, + + .enet0 = { + .has_phy = 1, + .use_internal_phy = 1, + }, + + .enet1 = { + .force_speed_100 = 1, + .force_duplex_full = 1, + }, + + + .has_ohci0 = 1, + .has_pccard = 1, + .has_ehci0 = 1, +}; +#endif + +/* + * all boards + */ +static const struct board_info __initdata *bcm963xx_boards[] = { +#ifdef CONFIG_BCM63XX_CPU_6348 + &board_96348r, + &board_96348gw, +#endif + +#ifdef CONFIG_BCM63XX_CPU_6358 + &board_96358vw2, +#endif +}; + +/* + * early init callback, read nvram data from flash and checksum it + */ +void __init board_prom_init(void) +{ + unsigned int check_len, i; + u8 *boot_addr, *cfe, *p; + char cfe_version[32]; + u32 val; + + /* read base address of boot chip select (0) */ + val = bcm_mpi_readl(MPI_CSBASE_REG(0)); + val &= MPI_CSBASE_BASE_MASK; + boot_addr = (u8 *)KSEG1ADDR(val); + + /* dump cfe version */ + cfe = boot_addr + BCM963XX_CFE_VERSION_OFFSET; + if (!memcmp(cfe, "cfe-v", 5)) + snprintf(cfe_version, sizeof(cfe_version), "%u.%u.%u-%u.%u", + cfe[5], cfe[6], cfe[7], cfe[8], cfe[9]); + else + strcpy(cfe_version, "unknown"); + printk(KERN_INFO PFX "CFE version: %s\n", cfe_version); + + /* extract nvram data */ + memcpy(&nvram, boot_addr + BCM963XX_NVRAM_OFFSET, sizeof(nvram)); + + /* check checksum before using data */ + if (nvram.version <= 4) + check_len = offsetof(struct bcm963xx_nvram, checksum_old); + else + check_len = sizeof(nvram); + val = 0; + p = (u8 *)&nvram; + while (check_len--) + val += *p; + if (val) { + printk(KERN_ERR PFX "invalid nvram checksum\n"); + return; + } + + /* find board by name */ + for (i = 0; i < ARRAY_SIZE(bcm963xx_boards); i++) { + if (strncmp(nvram.name, bcm963xx_boards[i]->name, + sizeof(nvram.name))) + continue; + /* copy, board desc array is marked initdata */ + memcpy(&board, bcm963xx_boards[i], sizeof(board)); + break; + } + + /* bail out if board is not found, will complain later */ + if (!board.name) + return; + + /* setup pin multiplexing depending on board enabled device, + * this has to be done this early since PCI init is done + * inside arch_initcall */ + val = 0; + + if (board.has_pci) { + bcm63xx_pci_enabled = 1; + if (BCMCPU_IS_6348()) + val |= GPIO_MODE_6348_G2_PCI; + } + + if (board.has_pccard) { + if (BCMCPU_IS_6348()) + val |= GPIO_MODE_6348_G1_MII_PCCARD; + } + + if (board.has_enet0 && !board.enet0.use_internal_phy) { + if (BCMCPU_IS_6348()) + val |= GPIO_MODE_6348_G3_EXT_MII | + GPIO_MODE_6348_G0_EXT_MII; + } + + if (board.has_enet1 && !board.enet1.use_internal_phy) { + if (BCMCPU_IS_6348()) + val |= GPIO_MODE_6348_G3_EXT_MII | + GPIO_MODE_6348_G0_EXT_MII; + } + + bcm_gpio_writel(val, GPIO_MODE_REG); +} + +/* + * second stage init callback, good time to panic if we couldn't + * identify on which board we're running since early printk is working + */ +void __init board_setup(void) +{ + if (!board.name) + panic("unable to detect bcm963xx board"); + printk(KERN_INFO PFX "board name: %s\n", board.name); + + /* make sure we're running on expected cpu */ + if (bcm63xx_get_cpu_id() != board.expected_cpu_id) + panic("unexpected CPU for bcm963xx board"); +} + +/* + * return board name for /proc/cpuinfo + */ +const char *board_get_name(void) +{ + return board.name; +} + +/* + * register & return a new board mac address + */ +static int board_get_mac_address(u8 *mac) +{ + u8 *p; + int count; + + if (mac_addr_used >= nvram.mac_addr_count) { + printk(KERN_ERR PFX "not enough mac address\n"); + return -ENODEV; + } + + memcpy(mac, nvram.mac_addr_base, ETH_ALEN); + p = mac + ETH_ALEN - 1; + count = mac_addr_used; + + while (count--) { + do { + (*p)++; + if (*p != 0) + break; + p--; + } while (p != mac); + } + + if (p == mac) { + printk(KERN_ERR PFX "unable to fetch mac address\n"); + return -ENODEV; + } + + mac_addr_used++; + return 0; +} + +static struct mtd_partition mtd_partitions[] = { + { + .name = "cfe", + .offset = 0x0, + .size = 0x40000, + } +}; + +static struct physmap_flash_data flash_data = { + .width = 2, + .nr_parts = ARRAY_SIZE(mtd_partitions), + .parts = mtd_partitions, +}; + +static struct resource mtd_resources[] = { + { + .start = 0, /* filled at runtime */ + .end = 0, /* filled at runtime */ + .flags = IORESOURCE_MEM, + } +}; + +static struct platform_device mtd_dev = { + .name = "physmap-flash", + .resource = mtd_resources, + .num_resources = ARRAY_SIZE(mtd_resources), + .dev = { + .platform_data = &flash_data, + }, +}; + +/* + * third stage init callback, register all board devices. + */ +int __init board_register_devices(void) +{ + u32 val; + + bcm63xx_uart_register(); + + if (board.has_pccard) + bcm63xx_pcmcia_register(); + + if (board.has_enet0 && + !board_get_mac_address(board.enet0.mac_addr)) + bcm63xx_enet_register(0, &board.enet0); + + if (board.has_enet1 && + !board_get_mac_address(board.enet1.mac_addr)) + bcm63xx_enet_register(1, &board.enet1); + + if (board.has_ohci0) + bcm63xx_ohci_register(); + + if (board.has_ehci0) + bcm63xx_ehci_register(); + + + /* read base address of boot chip select (0) */ + val = bcm_mpi_readl(MPI_CSBASE_REG(0)); + val &= MPI_CSBASE_BASE_MASK; + mtd_resources[0].start = val; + mtd_resources[0].end = 0x1FFFFFFF; + + platform_device_register(&mtd_dev); + + return 0; +} + diff --git a/arch/mips/bcm63xx/prom.c b/arch/mips/bcm63xx/prom.c index f0b49e8..d97ceed 100644 --- a/arch/mips/bcm63xx/prom.c +++ b/arch/mips/bcm63xx/prom.c @@ -9,6 +9,7 @@ #include #include #include +#include #include #include #include @@ -36,6 +37,9 @@ void __init prom_init(void) /* assign command line from kernel config */ strcpy(arcs_cmdline, CONFIG_CMDLINE); + + /* do low level board init */ + board_prom_init(); } void __init prom_free_prom_memory(void) diff --git a/arch/mips/bcm63xx/setup.c b/arch/mips/bcm63xx/setup.c index 4d8b127..c4516fb 100644 --- a/arch/mips/bcm63xx/setup.c +++ b/arch/mips/bcm63xx/setup.c @@ -16,6 +16,7 @@ #include #include #include +#include #include #include #include @@ -87,8 +88,9 @@ static void __bcm63xx_machine_reboot(char *p) const char *get_system_type(void) { static char buf[128]; - sprintf(buf, "bcm963xx (0x%04x/0x%04X)", - bcm63xx_get_cpu_id(), bcm63xx_get_cpu_rev()); + snprintf(buf, sizeof (buf), "bcm63xx/%s (0x%04x/0x%04X)", + board_get_name(), + bcm63xx_get_cpu_id(), bcm63xx_get_cpu_rev()); return buf; } @@ -96,6 +98,7 @@ void __init plat_time_init(void) { mips_hpt_frequency = bcm63xx_get_cpu_freq() / 2; } + void __init plat_mem_setup(void) { add_memory_region(0, bcm63xx_get_memory_size(), BOOT_MEM_RAM); @@ -107,4 +110,13 @@ void __init plat_mem_setup(void) set_io_port_base(0); ioport_resource.start = 0; ioport_resource.end = ~0; + + board_setup(); +} + +int __init bcm63xx_register_devices(void) +{ + return board_register_devices(); } + +device_initcall(bcm63xx_register_devices); diff --git a/include/asm-mips/mach-bcm63xx/bcm63xx_board.h b/include/asm-mips/mach-bcm63xx/bcm63xx_board.h new file mode 100644 index 0000000..fa3e7e6 --- /dev/null +++ b/include/asm-mips/mach-bcm63xx/bcm63xx_board.h @@ -0,0 +1,12 @@ +#ifndef BCM63XX_BOARD_H_ +#define BCM63XX_BOARD_H_ + +const char *board_get_name(void); + +void board_prom_init(void); + +void board_setup(void); + +int board_register_devices(void); + +#endif /* ! BCM63XX_BOARD_H_ */ diff --git a/include/asm-mips/mach-bcm63xx/board_bcm963xx.h b/include/asm-mips/mach-bcm63xx/board_bcm963xx.h new file mode 100644 index 0000000..17e4e7e --- /dev/null +++ b/include/asm-mips/mach-bcm63xx/board_bcm963xx.h @@ -0,0 +1,50 @@ +#ifndef BOARD_BCM963XX_H_ +#define BOARD_BCM963XX_H_ + +#include +#include + +/* + * flash mapping + */ +#define BCM963XX_CFE_VERSION_OFFSET 0x570 +#define BCM963XX_NVRAM_OFFSET 0x580 + +/* + * nvram structure + */ +struct bcm963xx_nvram { + u32 version; + u8 reserved1[256]; + u8 name[16]; + u32 main_tp_number; + u32 psi_size; + u32 mac_addr_count; + u8 mac_addr_base[6]; + u8 reserved2[2]; + u32 checksum_old; + u8 reserved3[720]; + u32 checksum_high; +}; + +/* + * board definition + */ +struct board_info { + u8 name[16]; + unsigned int expected_cpu_id; + + /* enabled feature/device */ + unsigned int has_enet0:1; + unsigned int has_enet1:1; + unsigned int has_pci:1; + unsigned int has_pccard:1; + unsigned int has_ohci0:1; + unsigned int has_ehci0:1; + + /* ethernet config */ + struct bcm63xx_enet_platform_data enet0; + struct bcm63xx_enet_platform_data enet1; +}; + +#endif /* ! BOARD_BCM963XX_H_ */ -- 1.5.4.3