1 | // SPDX-License-Identifier: GPL-2.0 |
2 | /* |
3 | * Renesas Technology Sales RTS7751R2D Support. |
4 | * |
5 | * Copyright (C) 2002 - 2006 Atom Create Engineering Co., Ltd. |
6 | * Copyright (C) 2004 - 2007 Paul Mundt |
7 | */ |
8 | #include <linux/init.h> |
9 | #include <linux/platform_device.h> |
10 | #include <linux/mtd/mtd.h> |
11 | #include <linux/mtd/partitions.h> |
12 | #include <linux/mtd/physmap.h> |
13 | #include <linux/ata_platform.h> |
14 | #include <linux/sm501.h> |
15 | #include <linux/sm501-regs.h> |
16 | #include <linux/pm.h> |
17 | #include <linux/fb.h> |
18 | #include <linux/spi/spi.h> |
19 | #include <linux/spi/spi_bitbang.h> |
20 | #include <asm/machvec.h> |
21 | #include <mach/r2d.h> |
22 | #include <asm/io.h> |
23 | #include <asm/io_trapped.h> |
24 | #include <asm/spi.h> |
25 | |
26 | static struct resource cf_ide_resources[] = { |
27 | [0] = { |
28 | .start = PA_AREA5_IO + 0x1000, |
29 | .end = PA_AREA5_IO + 0x1000 + 0x10 - 0x2, |
30 | .flags = IORESOURCE_MEM, |
31 | }, |
32 | [1] = { |
33 | .start = PA_AREA5_IO + 0x80c, |
34 | .end = PA_AREA5_IO + 0x80c, |
35 | .flags = IORESOURCE_MEM, |
36 | }, |
37 | #ifndef CONFIG_RTS7751R2D_1 /* For R2D-1 polling is preferred */ |
38 | [2] = { |
39 | .start = IRQ_CF_IDE, |
40 | .flags = IORESOURCE_IRQ, |
41 | }, |
42 | #endif |
43 | }; |
44 | |
45 | static struct pata_platform_info pata_info = { |
46 | .ioport_shift = 1, |
47 | }; |
48 | |
49 | static struct platform_device cf_ide_device = { |
50 | .name = "pata_platform" , |
51 | .id = -1, |
52 | .num_resources = ARRAY_SIZE(cf_ide_resources), |
53 | .resource = cf_ide_resources, |
54 | .dev = { |
55 | .platform_data = &pata_info, |
56 | }, |
57 | }; |
58 | |
59 | static struct spi_board_info spi_bus[] = { |
60 | { |
61 | .modalias = "rtc-r9701" , |
62 | .max_speed_hz = 1000000, |
63 | .mode = SPI_MODE_3, |
64 | }, |
65 | }; |
66 | |
67 | static void r2d_chip_select(struct sh_spi_info *spi, int cs, int state) |
68 | { |
69 | BUG_ON(cs != 0); /* Single Epson RTC-9701JE attached on CS0 */ |
70 | __raw_writew(val: state == BITBANG_CS_ACTIVE, addr: PA_RTCCE); |
71 | } |
72 | |
73 | static struct sh_spi_info spi_info = { |
74 | .num_chipselect = 1, |
75 | .chip_select = r2d_chip_select, |
76 | }; |
77 | |
78 | static struct resource spi_sh_sci_resources[] = { |
79 | { |
80 | .start = 0xffe00000, |
81 | .end = 0xffe0001f, |
82 | .flags = IORESOURCE_MEM, |
83 | }, |
84 | }; |
85 | |
86 | static struct platform_device spi_sh_sci_device = { |
87 | .name = "spi_sh_sci" , |
88 | .id = -1, |
89 | .num_resources = ARRAY_SIZE(spi_sh_sci_resources), |
90 | .resource = spi_sh_sci_resources, |
91 | .dev = { |
92 | .platform_data = &spi_info, |
93 | }, |
94 | }; |
95 | |
96 | static struct resource heartbeat_resources[] = { |
97 | [0] = { |
98 | .start = PA_OUTPORT, |
99 | .end = PA_OUTPORT, |
100 | .flags = IORESOURCE_MEM, |
101 | }, |
102 | }; |
103 | |
104 | static struct platform_device heartbeat_device = { |
105 | .name = "heartbeat" , |
106 | .id = -1, |
107 | .num_resources = ARRAY_SIZE(heartbeat_resources), |
108 | .resource = heartbeat_resources, |
109 | }; |
110 | |
111 | static struct resource sm501_resources[] = { |
112 | [0] = { |
113 | .start = 0x10000000, |
114 | .end = 0x13e00000 - 1, |
115 | .flags = IORESOURCE_MEM, |
116 | }, |
117 | [1] = { |
118 | .start = 0x13e00000, |
119 | .end = 0x13ffffff, |
120 | .flags = IORESOURCE_MEM, |
121 | }, |
122 | [2] = { |
123 | .start = IRQ_VOYAGER, |
124 | .flags = IORESOURCE_IRQ, |
125 | }, |
126 | }; |
127 | |
128 | static struct fb_videomode sm501_default_mode = { |
129 | .pixclock = 35714, |
130 | .xres = 640, |
131 | .yres = 480, |
132 | .left_margin = 105, |
133 | .right_margin = 50, |
134 | .upper_margin = 35, |
135 | .lower_margin = 0, |
136 | .hsync_len = 96, |
137 | .vsync_len = 2, |
138 | .sync = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, |
139 | }; |
140 | |
141 | static struct sm501_platdata_fbsub sm501_pdata_fbsub_pnl = { |
142 | .def_bpp = 16, |
143 | .def_mode = &sm501_default_mode, |
144 | .flags = SM501FB_FLAG_USE_INIT_MODE | |
145 | SM501FB_FLAG_USE_HWCURSOR | |
146 | SM501FB_FLAG_USE_HWACCEL | |
147 | SM501FB_FLAG_DISABLE_AT_EXIT, |
148 | }; |
149 | |
150 | static struct sm501_platdata_fbsub sm501_pdata_fbsub_crt = { |
151 | .flags = (SM501FB_FLAG_USE_INIT_MODE | |
152 | SM501FB_FLAG_USE_HWCURSOR | |
153 | SM501FB_FLAG_USE_HWACCEL | |
154 | SM501FB_FLAG_DISABLE_AT_EXIT), |
155 | |
156 | }; |
157 | |
158 | static struct sm501_platdata_fb sm501_fb_pdata = { |
159 | .fb_route = SM501_FB_OWN, |
160 | .fb_crt = &sm501_pdata_fbsub_crt, |
161 | .fb_pnl = &sm501_pdata_fbsub_pnl, |
162 | .flags = SM501_FBPD_SWAP_FB_ENDIAN, |
163 | }; |
164 | |
165 | static struct sm501_initdata sm501_initdata = { |
166 | .devices = SM501_USE_USB_HOST | SM501_USE_UART0, |
167 | }; |
168 | |
169 | static struct sm501_platdata sm501_platform_data = { |
170 | .init = &sm501_initdata, |
171 | .fb = &sm501_fb_pdata, |
172 | }; |
173 | |
174 | static struct platform_device sm501_device = { |
175 | .name = "sm501" , |
176 | .id = -1, |
177 | .dev = { |
178 | .platform_data = &sm501_platform_data, |
179 | }, |
180 | .num_resources = ARRAY_SIZE(sm501_resources), |
181 | .resource = sm501_resources, |
182 | }; |
183 | |
184 | static struct mtd_partition r2d_partitions[] = { |
185 | { |
186 | .name = "U-Boot" , |
187 | .offset = 0x00000000, |
188 | .size = 0x00040000, |
189 | .mask_flags = MTD_WRITEABLE, |
190 | }, { |
191 | .name = "Environment" , |
192 | .offset = MTDPART_OFS_NXTBLK, |
193 | .size = 0x00040000, |
194 | .mask_flags = MTD_WRITEABLE, |
195 | }, { |
196 | .name = "Kernel" , |
197 | .offset = MTDPART_OFS_NXTBLK, |
198 | .size = 0x001c0000, |
199 | }, { |
200 | .name = "Flash_FS" , |
201 | .offset = MTDPART_OFS_NXTBLK, |
202 | .size = MTDPART_SIZ_FULL, |
203 | } |
204 | }; |
205 | |
206 | static struct physmap_flash_data flash_data = { |
207 | .width = 2, |
208 | .nr_parts = ARRAY_SIZE(r2d_partitions), |
209 | .parts = r2d_partitions, |
210 | }; |
211 | |
212 | static struct resource flash_resource = { |
213 | .start = 0x00000000, |
214 | .end = 0x02000000, |
215 | .flags = IORESOURCE_MEM, |
216 | }; |
217 | |
218 | static struct platform_device flash_device = { |
219 | .name = "physmap-flash" , |
220 | .id = -1, |
221 | .resource = &flash_resource, |
222 | .num_resources = 1, |
223 | .dev = { |
224 | .platform_data = &flash_data, |
225 | }, |
226 | }; |
227 | |
228 | static struct platform_device *rts7751r2d_devices[] __initdata = { |
229 | &sm501_device, |
230 | &heartbeat_device, |
231 | &spi_sh_sci_device, |
232 | }; |
233 | |
234 | /* |
235 | * The CF is connected with a 16-bit bus where 8-bit operations are |
236 | * unsupported. The linux ata driver is however using 8-bit operations, so |
237 | * insert a trapped io filter to convert 8-bit operations into 16-bit. |
238 | */ |
239 | static struct trapped_io cf_trapped_io = { |
240 | .resource = cf_ide_resources, |
241 | .num_resources = 2, |
242 | .minimum_bus_width = 16, |
243 | }; |
244 | |
245 | static int __init rts7751r2d_devices_setup(void) |
246 | { |
247 | if (register_trapped_io(&cf_trapped_io) == 0) |
248 | platform_device_register(&cf_ide_device); |
249 | |
250 | if (mach_is_r2d_plus()) |
251 | platform_device_register(&flash_device); |
252 | |
253 | spi_register_board_info(info: spi_bus, ARRAY_SIZE(spi_bus)); |
254 | |
255 | return platform_add_devices(rts7751r2d_devices, |
256 | ARRAY_SIZE(rts7751r2d_devices)); |
257 | } |
258 | device_initcall(rts7751r2d_devices_setup); |
259 | |
260 | static void rts7751r2d_power_off(void) |
261 | { |
262 | __raw_writew(val: 0x0001, addr: PA_POWOFF); |
263 | } |
264 | |
265 | /* |
266 | * Initialize the board |
267 | */ |
268 | static void __init rts7751r2d_setup(char **cmdline_p) |
269 | { |
270 | void __iomem *sm501_reg; |
271 | u16 ver = __raw_readw(addr: PA_VERREG); |
272 | |
273 | printk(KERN_INFO "Renesas Technology Sales RTS7751R2D support.\n" ); |
274 | |
275 | printk(KERN_INFO "FPGA version:%d (revision:%d)\n" , |
276 | (ver >> 4) & 0xf, ver & 0xf); |
277 | |
278 | __raw_writew(val: 0x0000, addr: PA_OUTPORT); |
279 | pm_power_off = rts7751r2d_power_off; |
280 | |
281 | /* sm501 dram configuration: |
282 | * ColSizeX = 11 - External Memory Column Size: 256 words. |
283 | * APX = 1 - External Memory Active to Pre-Charge Delay: 7 clocks. |
284 | * RstX = 1 - External Memory Reset: Normal. |
285 | * Rfsh = 1 - Local Memory Refresh to Command Delay: 12 clocks. |
286 | * BwC = 1 - Local Memory Block Write Cycle Time: 2 clocks. |
287 | * BwP = 1 - Local Memory Block Write to Pre-Charge Delay: 1 clock. |
288 | * AP = 1 - Internal Memory Active to Pre-Charge Delay: 7 clocks. |
289 | * Rst = 1 - Internal Memory Reset: Normal. |
290 | * RA = 1 - Internal Memory Remain in Active State: Do not remain. |
291 | */ |
292 | |
293 | sm501_reg = (void __iomem *)0xb3e00000 + SM501_DRAM_CONTROL; |
294 | writel(readl(addr: sm501_reg) | 0x00f107c0, addr: sm501_reg); |
295 | } |
296 | |
297 | /* |
298 | * The Machine Vector |
299 | */ |
300 | static struct sh_machine_vector mv_rts7751r2d __initmv = { |
301 | .mv_name = "RTS7751R2D" , |
302 | .mv_setup = rts7751r2d_setup, |
303 | .mv_init_irq = init_rts7751r2d_IRQ, |
304 | .mv_irq_demux = rts7751r2d_irq_demux, |
305 | }; |
306 | |