1 /* 2 * arch/arm/mach-ep93xx/ts72xx.c 3 * Technologic Systems TS72xx SBC support. 4 * 5 * Copyright (C) 2006 Lennert Buytenhek <buytenh@wantstofly.org> 6 * 7 * This program is free software; you can redistribute it and/or modify 8 * it under the terms of the GNU General Public License as published by 9 * the Free Software Foundation; either version 2 of the License, or (at 10 * your option) any later version. 11 */ 12 13 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 14 15 #include <linux/kernel.h> 16 #include <linux/init.h> 17 #include <linux/platform_device.h> 18 #include <linux/io.h> 19 #include <linux/m48t86.h> 20 #include <linux/mtd/nand.h> 21 #include <linux/mtd/partitions.h> 22 23 #include <mach/hardware.h> 24 #include <mach/ts72xx.h> 25 26 #include <asm/mach-types.h> 27 #include <asm/mach/map.h> 28 #include <asm/mach/arch.h> 29 30 31 static struct map_desc ts72xx_io_desc[] __initdata = { 32 { 33 .virtual = TS72XX_MODEL_VIRT_BASE, 34 .pfn = __phys_to_pfn(TS72XX_MODEL_PHYS_BASE), 35 .length = TS72XX_MODEL_SIZE, 36 .type = MT_DEVICE, 37 }, { 38 .virtual = TS72XX_OPTIONS_VIRT_BASE, 39 .pfn = __phys_to_pfn(TS72XX_OPTIONS_PHYS_BASE), 40 .length = TS72XX_OPTIONS_SIZE, 41 .type = MT_DEVICE, 42 }, { 43 .virtual = TS72XX_OPTIONS2_VIRT_BASE, 44 .pfn = __phys_to_pfn(TS72XX_OPTIONS2_PHYS_BASE), 45 .length = TS72XX_OPTIONS2_SIZE, 46 .type = MT_DEVICE, 47 }, { 48 .virtual = TS72XX_RTC_INDEX_VIRT_BASE, 49 .pfn = __phys_to_pfn(TS72XX_RTC_INDEX_PHYS_BASE), 50 .length = TS72XX_RTC_INDEX_SIZE, 51 .type = MT_DEVICE, 52 }, { 53 .virtual = TS72XX_RTC_DATA_VIRT_BASE, 54 .pfn = __phys_to_pfn(TS72XX_RTC_DATA_PHYS_BASE), 55 .length = TS72XX_RTC_DATA_SIZE, 56 .type = MT_DEVICE, 57 } 58 }; 59 60 static void __init ts72xx_map_io(void) 61 { 62 ep93xx_map_io(); 63 iotable_init(ts72xx_io_desc, ARRAY_SIZE(ts72xx_io_desc)); 64 } 65 66 67 /************************************************************************* 68 * NAND flash 69 *************************************************************************/ 70 #define TS72XX_NAND_CONTROL_ADDR_LINE 22 /* 0xN0400000 */ 71 #define TS72XX_NAND_BUSY_ADDR_LINE 23 /* 0xN0800000 */ 72 73 static void ts72xx_nand_hwcontrol(struct mtd_info *mtd, 74 int cmd, unsigned int ctrl) 75 { 76 struct nand_chip *chip = mtd->priv; 77 78 if (ctrl & NAND_CTRL_CHANGE) { 79 void __iomem *addr = chip->IO_ADDR_R; 80 unsigned char bits; 81 82 addr += (1 << TS72XX_NAND_CONTROL_ADDR_LINE); 83 84 bits = __raw_readb(addr) & ~0x07; 85 bits |= (ctrl & NAND_NCE) << 2; /* bit 0 -> bit 2 */ 86 bits |= (ctrl & NAND_CLE); /* bit 1 -> bit 1 */ 87 bits |= (ctrl & NAND_ALE) >> 2; /* bit 2 -> bit 0 */ 88 89 __raw_writeb(bits, addr); 90 } 91 92 if (cmd != NAND_CMD_NONE) 93 __raw_writeb(cmd, chip->IO_ADDR_W); 94 } 95 96 static int ts72xx_nand_device_ready(struct mtd_info *mtd) 97 { 98 struct nand_chip *chip = mtd->priv; 99 void __iomem *addr = chip->IO_ADDR_R; 100 101 addr += (1 << TS72XX_NAND_BUSY_ADDR_LINE); 102 103 return !!(__raw_readb(addr) & 0x20); 104 } 105 106 static const char *ts72xx_nand_part_probes[] = { "cmdlinepart", NULL }; 107 108 #define TS72XX_BOOTROM_PART_SIZE (SZ_16K) 109 #define TS72XX_REDBOOT_PART_SIZE (SZ_2M + SZ_1M) 110 111 static struct mtd_partition ts72xx_nand_parts[] = { 112 { 113 .name = "TS-BOOTROM", 114 .offset = 0, 115 .size = TS72XX_BOOTROM_PART_SIZE, 116 .mask_flags = MTD_WRITEABLE, /* force read-only */ 117 }, { 118 .name = "Linux", 119 .offset = MTDPART_OFS_APPEND, 120 .size = 0, /* filled in later */ 121 }, { 122 .name = "RedBoot", 123 .offset = MTDPART_OFS_APPEND, 124 .size = MTDPART_SIZ_FULL, 125 .mask_flags = MTD_WRITEABLE, /* force read-only */ 126 }, 127 }; 128 129 static void ts72xx_nand_set_parts(uint64_t size, 130 struct platform_nand_chip *chip) 131 { 132 /* Factory TS-72xx boards only come with 32MiB or 128MiB NAND options */ 133 if (size == SZ_32M || size == SZ_128M) { 134 /* Set the "Linux" partition size */ 135 ts72xx_nand_parts[1].size = size - TS72XX_REDBOOT_PART_SIZE; 136 137 chip->partitions = ts72xx_nand_parts; 138 chip->nr_partitions = ARRAY_SIZE(ts72xx_nand_parts); 139 } else { 140 pr_warning("Unknown nand disk size:%lluMiB\n", size >> 20); 141 } 142 } 143 144 static struct platform_nand_data ts72xx_nand_data = { 145 .chip = { 146 .nr_chips = 1, 147 .chip_offset = 0, 148 .chip_delay = 15, 149 .part_probe_types = ts72xx_nand_part_probes, 150 .set_parts = ts72xx_nand_set_parts, 151 }, 152 .ctrl = { 153 .cmd_ctrl = ts72xx_nand_hwcontrol, 154 .dev_ready = ts72xx_nand_device_ready, 155 }, 156 }; 157 158 static struct resource ts72xx_nand_resource[] = { 159 { 160 .start = 0, /* filled in later */ 161 .end = 0, /* filled in later */ 162 .flags = IORESOURCE_MEM, 163 }, 164 }; 165 166 static struct platform_device ts72xx_nand_flash = { 167 .name = "gen_nand", 168 .id = -1, 169 .dev.platform_data = &ts72xx_nand_data, 170 .resource = ts72xx_nand_resource, 171 .num_resources = ARRAY_SIZE(ts72xx_nand_resource), 172 }; 173 174 175 static void __init ts72xx_register_flash(void) 176 { 177 /* 178 * TS7200 has NOR flash all other TS72xx board have NAND flash. 179 */ 180 if (board_is_ts7200()) { 181 ep93xx_register_flash(2, EP93XX_CS6_PHYS_BASE, SZ_16M); 182 } else { 183 resource_size_t start; 184 185 if (is_ts9420_installed()) 186 start = EP93XX_CS7_PHYS_BASE; 187 else 188 start = EP93XX_CS6_PHYS_BASE; 189 190 ts72xx_nand_resource[0].start = start; 191 ts72xx_nand_resource[0].end = start + SZ_16M - 1; 192 193 platform_device_register(&ts72xx_nand_flash); 194 } 195 } 196 197 198 static unsigned char ts72xx_rtc_readbyte(unsigned long addr) 199 { 200 __raw_writeb(addr, TS72XX_RTC_INDEX_VIRT_BASE); 201 return __raw_readb(TS72XX_RTC_DATA_VIRT_BASE); 202 } 203 204 static void ts72xx_rtc_writebyte(unsigned char value, unsigned long addr) 205 { 206 __raw_writeb(addr, TS72XX_RTC_INDEX_VIRT_BASE); 207 __raw_writeb(value, TS72XX_RTC_DATA_VIRT_BASE); 208 } 209 210 static struct m48t86_ops ts72xx_rtc_ops = { 211 .readbyte = ts72xx_rtc_readbyte, 212 .writebyte = ts72xx_rtc_writebyte, 213 }; 214 215 static struct platform_device ts72xx_rtc_device = { 216 .name = "rtc-m48t86", 217 .id = -1, 218 .dev = { 219 .platform_data = &ts72xx_rtc_ops, 220 }, 221 .num_resources = 0, 222 }; 223 224 static struct resource ts72xx_wdt_resources[] = { 225 { 226 .start = TS72XX_WDT_CONTROL_PHYS_BASE, 227 .end = TS72XX_WDT_CONTROL_PHYS_BASE + SZ_4K - 1, 228 .flags = IORESOURCE_MEM, 229 }, 230 { 231 .start = TS72XX_WDT_FEED_PHYS_BASE, 232 .end = TS72XX_WDT_FEED_PHYS_BASE + SZ_4K - 1, 233 .flags = IORESOURCE_MEM, 234 }, 235 }; 236 237 static struct platform_device ts72xx_wdt_device = { 238 .name = "ts72xx-wdt", 239 .id = -1, 240 .num_resources = ARRAY_SIZE(ts72xx_wdt_resources), 241 .resource = ts72xx_wdt_resources, 242 }; 243 244 static struct ep93xx_eth_data __initdata ts72xx_eth_data = { 245 .phy_id = 1, 246 }; 247 248 static void __init ts72xx_init_machine(void) 249 { 250 ep93xx_init_devices(); 251 ts72xx_register_flash(); 252 platform_device_register(&ts72xx_rtc_device); 253 platform_device_register(&ts72xx_wdt_device); 254 255 ep93xx_register_eth(&ts72xx_eth_data, 1); 256 } 257 258 MACHINE_START(TS72XX, "Technologic Systems TS-72xx SBC") 259 /* Maintainer: Lennert Buytenhek <buytenh@wantstofly.org> */ 260 .boot_params = EP93XX_SDCE3_PHYS_BASE_SYNC + 0x100, 261 .map_io = ts72xx_map_io, 262 .init_irq = ep93xx_init_irq, 263 .timer = &ep93xx_timer, 264 .init_machine = ts72xx_init_machine, 265 MACHINE_END 266