/* * sysmocom sysmobts v2 board support. * Copyright (C) 2012 sysmocom s.f.m.c GmbH * Copyright (C) 2011 Lyrtech * * Based on SFF-SDR platform, original copyright follows: * Lyrtech SFFSDR board support. * * Copyright (C) 2008 Philip Balister, OpenSDR * Copyright (C) 2008 Lyrtech * * Based on DV-EVM platform, original copyright follows: * * Copyright (C) 2007 MontaVista Software, Inc. * * 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. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define SYSMOBTS_V2_PHY_ID "0:01" #define SYSMOBTS_V2_PHY_MASK (0x2) #define DAVINCI_ASYNC_EMIF_CONTROL_BASE 0x01e00000 #define DAVINCI_ASYNC_EMIF_DATA_CE0_BASE 0x02000000 #define DAVINCI_DSP_L1D_EMIF_BASE 0x11F04000 #define DAVINCI_DSP_L1D_EMIF_SIZE 0x00014000 #define DAVINCI_DSP_L1P_EMIF_BASE 0x11E08000 #define DAVINCI_DSP_L1P_EMIF_SIZE 0x00008000 #define DAVINCI_DSP_L2_EMIF_BASE 0x11800000 #define DAVINCI_DSP_L2_EMIF_SIZE 0x00010000 #define DAVINCI_DSP_DDR_EMIF_BASE 0x86D00000 #define DAVINCI_DSP_DDR_EMIF_SIZE 0x00600000 #define SYSMOBTS_V2_GPIO_BOARD_REV_D0 GPIO(15) #define SYSMOBTS_V2_GPIO_BOARD_REV_D1 GPIO(16) #define SYSMOBTS_V2_GPIO_BOARD_REV_D2 GPIO(17) #define SYSMOBTS_V2_GPIO_MMC_CD GPIO(7) #define SYSMOBTS_V2_GPIO_LED_RF_ACTIVITY GPIO(29) #define SYSMOBTS_V2_GPIO_LED_RF_ONLINE GPIO(31) #define SYSMOBTS_V2_GPIO_FPGA_BUSY GPIO(45) #define SYSMOBTS_V2_GPIO_FPGA_DONE GPIO(46) #define SYSMOBTS_V2_GPIO_FPGA_INIT_B GPIO(50) #define SYSMOBTS_V2_GPIO_FPGA_PROG_B GPIO(51) #define SYSMOBTS_V2_FPGA_SELECTMAP_BASE 0x04000000 #define FPGA_MEM_BASE (0x04000000) #define FPGA_MEM_SIZE (0x02000000) #define FPGA_UART0_MEM_BASE (0x04000800) #define FPGA_UART1_MEM_BASE (0x04000810) #define FPGA_UART0_IRQ GPIO(6) #define FPGA_UART1_IRQ GPIO(7) static struct plat_serial8250_port sysmobts_v2_multitrx_uart_platform_data[] = { { .mapbase = FPGA_UART0_MEM_BASE, .irq = 0, .flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST | UPF_IOREMAP, .iotype = UPIO_MEM, .regshift = 1, .uartclk = 54000000, }, { .mapbase = FPGA_UART1_MEM_BASE, .irq = 0, .flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST | UPF_IOREMAP, .iotype = UPIO_MEM, .regshift = 1, .uartclk = 54000000, }, { .flags = 0 }, }; static void sysmobts_v2_multitrx_uart_release(struct device *device) { } static struct platform_device sysmobts_v2_multitrx_uart_device; static struct platform_device sysmobts_v2_multitrx_uart_device_template = { .name = "serial8250", .id = PLAT8250_DEV_PLATFORM1, .dev = { .platform_data = sysmobts_v2_multitrx_uart_platform_data, .release = sysmobts_v2_multitrx_uart_release, }, }; struct mtd_partition sysmobts_v2_nandflash_partition[] = { /* U-Boot Environment: Block 0 * UBL: Block 1 * U-Boot: Blocks 6-7 (256 kb) * Kernel: Blocks 8-31 (3 Mb) * Linux Root: Blocks 32-287 (32 Mb) * User Storage: Blocks 288-END */ { .name = "U-Boot Environment", .offset = 0, .size = SZ_128K, .mask_flags = MTD_WRITEABLE, /* force read-only */ }, { .name = "UBL", .offset = MTDPART_OFS_APPEND, .size = 3 * SZ_128K, .mask_flags = 0, }, { .name = "U-Boot", .offset = MTDPART_OFS_APPEND, .size = 4 * SZ_128K, .mask_flags = 0, }, { .name = "RootFs", .offset = MTDPART_OFS_APPEND, .size = MTDPART_SIZ_FULL, .mask_flags = 0 } }; static struct davinci_nand_pdata sysmobts_v2_nandflash_data = { .parts = sysmobts_v2_nandflash_partition, .nr_parts = ARRAY_SIZE(sysmobts_v2_nandflash_partition), .ecc_mode = NAND_ECC_HW, .bbt_options = NAND_BBT_USE_FLASH, }; static struct resource sysmobts_v2_nandflash_resource[] = { { .start = DAVINCI_ASYNC_EMIF_DATA_CE0_BASE, .end = DAVINCI_ASYNC_EMIF_DATA_CE0_BASE + 0x1F, .flags = IORESOURCE_MEM, }, { .start = DAVINCI_ASYNC_EMIF_CONTROL_BASE, .end = DAVINCI_ASYNC_EMIF_CONTROL_BASE + SZ_4K - 1, .flags = IORESOURCE_MEM, }, }; static struct platform_device sysmobts_v2_nandflash_device = { .name = "davinci_nand", /* Name of driver */ .id = 0, .dev = { .platform_data = &sysmobts_v2_nandflash_data, }, .num_resources = ARRAY_SIZE(sysmobts_v2_nandflash_resource), .resource = sysmobts_v2_nandflash_resource, }; static struct at24_platform_data eeprom_info = { .byte_len = (2*1024) / 8, .page_size = 8, .flags = 0, .setup = davinci_get_mac_addr, .context = (void *)0x0000, }; static struct at24_platform_data eeprom_info_revD = { .byte_len = (64*1024) / 8, .page_size = 32, .flags = AT24_FLAG_ADDR16, .setup = davinci_get_mac_addr, .context = (void *)0x0000, }; /* TPS65023 voltage regulator support */ /* 1.2V Core */ static struct regulator_consumer_supply tps65023_dcdc1[] = { { .supply = "1.2V_core", }, }; /* 1.8V I/O */ static struct regulator_consumer_supply tps65023_dcdc2[] = { { .supply = "1.8V_io", }, }; /* 3.3V I/O */ static struct regulator_consumer_supply tps65023_dcdc3[] = { { .supply = "3.3V_io", }, }; /* 1.8V PLL */ static struct regulator_consumer_supply tps65023_ldo1[] = { { .supply = "1.8V_pll", }, }; /* Unused */ static struct regulator_consumer_supply tps65023_ldo2[] = { { .supply = "unused", }, }; static struct regulator_init_data tps65023_regulator_data[] = { /* dcdc1 */ { .constraints = { .min_uV = 1150000, .max_uV = 1350000, .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE, .always_on = 1, .boot_on = 1, }, .num_consumer_supplies = ARRAY_SIZE(tps65023_dcdc1), .consumer_supplies = tps65023_dcdc1, }, /* dcdc2 */ { .constraints = { .min_uV = 1800000, .max_uV = 1800000, .always_on = 1, .boot_on = 1, }, .num_consumer_supplies = ARRAY_SIZE(tps65023_dcdc2), .consumer_supplies = tps65023_dcdc2, }, /* dcdc3 */ { .constraints = { .min_uV = 3300000, .max_uV = 3300000, .always_on = 1, .boot_on = 1, }, .num_consumer_supplies = ARRAY_SIZE(tps65023_dcdc3), .consumer_supplies = tps65023_dcdc3, }, /* ldo1 */ { .constraints = { .min_uV = 1800000, .max_uV = 1800000, .always_on = 1, .boot_on = 1, }, .num_consumer_supplies = ARRAY_SIZE(tps65023_ldo1), .consumer_supplies = tps65023_ldo1, }, /* ldo2 */ { .constraints = { .min_uV = 2500000, .max_uV = 3300000, .boot_on = 1, .always_on = 1, }, .num_consumer_supplies = ARRAY_SIZE(tps65023_ldo2), .consumer_supplies = tps65023_ldo2, }, }; static struct i2c_board_info __initdata i2c_info[] = { { /* Ethernet EEPROM */ I2C_BOARD_INFO("24c02", 0x50), .platform_data = &eeprom_info, }, { /* Power Management IC */ I2C_BOARD_INFO("tps65023", 0x48), .platform_data = &tps65023_regulator_data[0], }, { /* Temperature Sensor */ I2C_BOARD_INFO("tmp411", 0x4D), }, }; static struct i2c_board_info __initdata i2c_info_revD[] = { { /* Ethernet EEPROM */ I2C_BOARD_INFO("24c64", 0x50), .platform_data = &eeprom_info_revD, }, { /* Power Management IC */ I2C_BOARD_INFO("tps65023", 0x48), .platform_data = &tps65023_regulator_data[0], }, { /* Temperature Sensor */ I2C_BOARD_INFO("tmp411", 0x4D), }, }; static struct davinci_i2c_platform_data i2c_pdata = { .bus_freq = 100 /* kHz */, .bus_delay = 2 /* usec */, .sda_pin = 44 /* for bus recovery */, .scl_pin = 43 /* for bus recovery */, }; static int __init sysmobts_v2_get_board_rev(void) { int boardRev; gpio_request(SYSMOBTS_V2_GPIO_BOARD_REV_D0, "board rev (b0)"); gpio_request(SYSMOBTS_V2_GPIO_BOARD_REV_D1, "board rev (b1)"); gpio_request(SYSMOBTS_V2_GPIO_BOARD_REV_D2, "board rev (b2)"); gpio_direction_input(SYSMOBTS_V2_GPIO_BOARD_REV_D0); gpio_direction_input(SYSMOBTS_V2_GPIO_BOARD_REV_D1); gpio_direction_input(SYSMOBTS_V2_GPIO_BOARD_REV_D2); boardRev = ((gpio_get_value(SYSMOBTS_V2_GPIO_BOARD_REV_D0) != 0) << 0) | ((gpio_get_value(SYSMOBTS_V2_GPIO_BOARD_REV_D1) != 0) << 1) | ((gpio_get_value(SYSMOBTS_V2_GPIO_BOARD_REV_D2) != 0) << 2); gpio_free(SYSMOBTS_V2_GPIO_BOARD_REV_D0); gpio_free(SYSMOBTS_V2_GPIO_BOARD_REV_D1); gpio_free(SYSMOBTS_V2_GPIO_BOARD_REV_D2); return boardRev; } static void __init sysmobts_v2_init_i2c(void) { davinci_init_i2c(&i2c_pdata); /* Install the info with the right EEPROM address */ if (sysmobts_v2_get_board_rev() <= 2) i2c_register_board_info(1, i2c_info, ARRAY_SIZE(i2c_info)); else i2c_register_board_info(1, i2c_info_revD, ARRAY_SIZE(i2c_info_revD)); } static void sysmobts_v2_teardown_fpga_device(void) { platform_device_unregister(&sysmobts_v2_multitrx_uart_device); gpio_free(FPGA_UART0_IRQ); gpio_free(FPGA_UART1_IRQ); } static void sysmobts_v2_setup_fpga_device(void) { sysmobts_v2_multitrx_uart_device = sysmobts_v2_multitrx_uart_device_template; gpio_request(FPGA_UART0_IRQ, "multi-trx uart0 irq"); gpio_direction_input(FPGA_UART0_IRQ); sysmobts_v2_multitrx_uart_platform_data[0].irq = gpio_to_irq(FPGA_UART0_IRQ); gpio_request(FPGA_UART1_IRQ, "multi-trx uart1 irq"); gpio_direction_input(FPGA_UART1_IRQ); sysmobts_v2_multitrx_uart_platform_data[1].irq = gpio_to_irq(FPGA_UART1_IRQ); platform_device_register(&sysmobts_v2_multitrx_uart_device); } static struct fpgadl_pdata_t sysmobts_v2_fpgadl_pdata = { .bitstream_max_size = 0x200000, .program_b = SYSMOBTS_V2_GPIO_FPGA_PROG_B, .done = SYSMOBTS_V2_GPIO_FPGA_DONE, .busy = SYSMOBTS_V2_GPIO_FPGA_BUSY, .init_b = SYSMOBTS_V2_GPIO_FPGA_INIT_B, .setup = sysmobts_v2_setup_fpga_device, .teardown = sysmobts_v2_teardown_fpga_device, }; static struct resource sysmobts_v2_fpgadl_resources[] = { { .name = "selectmap", .start = SYSMOBTS_V2_FPGA_SELECTMAP_BASE, .end = SYSMOBTS_V2_FPGA_SELECTMAP_BASE + 4 - 1, .flags = IORESOURCE_MEM, } }; static struct platform_device sysmobts_v2_fpgadl_device = { .name = "fpgadl_par", .id = 0, .dev = { .platform_data = &sysmobts_v2_fpgadl_pdata, }, .num_resources = ARRAY_SIZE(sysmobts_v2_fpgadl_resources), .resource = sysmobts_v2_fpgadl_resources, }; static struct resource sysmobts_v2_dspdl_resources[] = { { .name = "l1d", .start = DAVINCI_DSP_L1D_EMIF_BASE, .end = DAVINCI_DSP_L1D_EMIF_BASE + DAVINCI_DSP_L1D_EMIF_SIZE - 1, .flags = IORESOURCE_MEM, }, { .name = "l1p", .start = DAVINCI_DSP_L1P_EMIF_BASE, .end = DAVINCI_DSP_L1P_EMIF_BASE + DAVINCI_DSP_L1P_EMIF_SIZE - 1, .flags = IORESOURCE_MEM, }, { .name = "l2", .start = DAVINCI_DSP_L2_EMIF_BASE, .end = DAVINCI_DSP_L2_EMIF_BASE + DAVINCI_DSP_L2_EMIF_SIZE - 1, .flags = IORESOURCE_MEM, }, { .name = "ddr", .start = DAVINCI_DSP_DDR_EMIF_BASE, .end = DAVINCI_DSP_DDR_EMIF_BASE + DAVINCI_DSP_DDR_EMIF_SIZE - 1, .flags = IORESOURCE_MEM, } }; static struct platform_device sysmobts_v2_dspdl_device = { .name = "dspdl_dm644x", .id = 0, .num_resources = ARRAY_SIZE(sysmobts_v2_dspdl_resources), .resource = sysmobts_v2_dspdl_resources, }; static int sysmobts_v2_mmc_get_cd(int module) { /* low == card present */ return !gpio_get_value_cansleep(SYSMOBTS_V2_GPIO_MMC_CD); } static int sysmobts_v2_mmc_get_ro(int module) { /* high == card's write protect switch active */ return 0; } static struct davinci_mmc_config sysmobts_v2_mmc_config = { .get_cd = sysmobts_v2_mmc_get_cd, .get_ro = sysmobts_v2_mmc_get_ro, .wires = 4, .version = MMC_CTLR_VERSION_1 }; static struct gpio_led sysmobts_v2_gpio_leds[] = { { .name = "activity_led", .gpio = SYSMOBTS_V2_GPIO_LED_RF_ACTIVITY, }, { .name = "online_led", .gpio = SYSMOBTS_V2_GPIO_LED_RF_ONLINE, }, }; static struct gpio_led_platform_data sysmobts_v2_gpio_leds_info = { .leds = sysmobts_v2_gpio_leds, .num_leds = ARRAY_SIZE(sysmobts_v2_gpio_leds), }; static struct platform_device sysmobts_v2_led_device = { .name = "leds-gpio", .id = -1, .dev = { .platform_data = &sysmobts_v2_gpio_leds_info, }, }; static struct platform_device *sysmobts_v2_devices[] __initdata = { &sysmobts_v2_led_device, &sysmobts_v2_fpgadl_device, &sysmobts_v2_dspdl_device, &sysmobts_v2_nandflash_device, }; static struct davinci_uart_config uart_config __initdata = { .enabled_uarts = (1 << 0) | (1 << 1) | (1 << 2), }; static void __init sysmobts_v2_map_io(void) { dm644x_init(); } static void __init sysmobts_v2_reserve(void) { if (memblock_remove(DAVINCI_DSP_DDR_EMIF_BASE, DAVINCI_DSP_DDR_EMIF_SIZE)) { printk(KERN_ERR "Failed to reserve memory for DSP device (%d KB at 0x%08x)\n", DAVINCI_DSP_DDR_EMIF_SIZE/1024, DAVINCI_DSP_DDR_EMIF_BASE); } else { printk(KERN_ERR "Reserved DSP memory: %d KB at 0x%08x\n", DAVINCI_DSP_DDR_EMIF_SIZE/1024, DAVINCI_DSP_DDR_EMIF_BASE); } } static __init void sysmobts_v2_init(void) { struct davinci_soc_info *soc_info = &davinci_soc_info; platform_add_devices(sysmobts_v2_devices, ARRAY_SIZE(sysmobts_v2_devices)); sysmobts_v2_init_i2c(); davinci_serial_init(&uart_config); soc_info->emac_pdata->phy_id = SYSMOBTS_V2_PHY_ID; regulator_has_full_constraints(); davinci_setup_mmc(0, &sysmobts_v2_mmc_config); } MACHINE_START(SYSMOBTS_V2, "sysmocom sysmobts v2") .atag_offset = 0x100, .reserve = sysmobts_v2_reserve, .map_io = sysmobts_v2_map_io, .init_irq = davinci_irq_init, .timer = &davinci_timer, .init_machine = sysmobts_v2_init, .dma_zone_size = SZ_128M, MACHINE_END