impd1.c 8.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409
  1. /*
  2. * linux/arch/arm/mach-integrator/impd1.c
  3. *
  4. * Copyright (C) 2003 Deep Blue Solutions Ltd, All Rights Reserved.
  5. *
  6. * This program is free software; you can redistribute it and/or modify
  7. * it under the terms of the GNU General Public License version 2 as
  8. * published by the Free Software Foundation.
  9. *
  10. * This file provides the core support for the IM-PD1 module.
  11. *
  12. * Module / boot parameters.
  13. * lmid=n impd1.lmid=n - set the logic module position in stack to 'n'
  14. */
  15. #include <linux/module.h>
  16. #include <linux/moduleparam.h>
  17. #include <linux/init.h>
  18. #include <linux/device.h>
  19. #include <linux/errno.h>
  20. #include <linux/mm.h>
  21. #include <linux/amba/bus.h>
  22. #include <linux/amba/clcd.h>
  23. #include <linux/io.h>
  24. #include <linux/platform_data/clk-integrator.h>
  25. #include <linux/slab.h>
  26. #include <mach/lm.h>
  27. #include <mach/impd1.h>
  28. #include <asm/sizes.h>
  29. static int module_id;
  30. module_param_named(lmid, module_id, int, 0444);
  31. MODULE_PARM_DESC(lmid, "logic module stack position");
  32. struct impd1_module {
  33. void __iomem *base;
  34. };
  35. void impd1_tweak_control(struct device *dev, u32 mask, u32 val)
  36. {
  37. struct impd1_module *impd1 = dev_get_drvdata(dev);
  38. u32 cur;
  39. val &= mask;
  40. cur = readl(impd1->base + IMPD1_CTRL) & ~mask;
  41. writel(cur | val, impd1->base + IMPD1_CTRL);
  42. }
  43. EXPORT_SYMBOL(impd1_tweak_control);
  44. /*
  45. * CLCD support
  46. */
  47. #define PANEL PROSPECTOR
  48. #define LTM10C209 1
  49. #define PROSPECTOR 2
  50. #define SVGA 3
  51. #define VGA 4
  52. #if PANEL == VGA
  53. #define PANELTYPE vga
  54. static struct clcd_panel vga = {
  55. .mode = {
  56. .name = "VGA",
  57. .refresh = 60,
  58. .xres = 640,
  59. .yres = 480,
  60. .pixclock = 39721,
  61. .left_margin = 40,
  62. .right_margin = 24,
  63. .upper_margin = 32,
  64. .lower_margin = 11,
  65. .hsync_len = 96,
  66. .vsync_len = 2,
  67. .sync = 0,
  68. .vmode = FB_VMODE_NONINTERLACED,
  69. },
  70. .width = -1,
  71. .height = -1,
  72. .tim2 = TIM2_BCD | TIM2_IPC,
  73. .cntl = CNTL_LCDTFT | CNTL_LCDVCOMP(1),
  74. .caps = CLCD_CAP_5551,
  75. .connector = IMPD1_CTRL_DISP_VGA,
  76. .bpp = 16,
  77. .grayscale = 0,
  78. };
  79. #elif PANEL == SVGA
  80. #define PANELTYPE svga
  81. static struct clcd_panel svga = {
  82. .mode = {
  83. .name = "SVGA",
  84. .refresh = 0,
  85. .xres = 800,
  86. .yres = 600,
  87. .pixclock = 27778,
  88. .left_margin = 20,
  89. .right_margin = 20,
  90. .upper_margin = 5,
  91. .lower_margin = 5,
  92. .hsync_len = 164,
  93. .vsync_len = 62,
  94. .sync = 0,
  95. .vmode = FB_VMODE_NONINTERLACED,
  96. },
  97. .width = -1,
  98. .height = -1,
  99. .tim2 = TIM2_BCD,
  100. .cntl = CNTL_LCDTFT | CNTL_LCDVCOMP(1),
  101. .connector = IMPD1_CTRL_DISP_VGA,
  102. .caps = CLCD_CAP_5551,
  103. .bpp = 16,
  104. .grayscale = 0,
  105. };
  106. #elif PANEL == PROSPECTOR
  107. #define PANELTYPE prospector
  108. static struct clcd_panel prospector = {
  109. .mode = {
  110. .name = "PROSPECTOR",
  111. .refresh = 0,
  112. .xres = 640,
  113. .yres = 480,
  114. .pixclock = 40000,
  115. .left_margin = 33,
  116. .right_margin = 64,
  117. .upper_margin = 36,
  118. .lower_margin = 7,
  119. .hsync_len = 64,
  120. .vsync_len = 25,
  121. .sync = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
  122. .vmode = FB_VMODE_NONINTERLACED,
  123. },
  124. .width = -1,
  125. .height = -1,
  126. .tim2 = TIM2_BCD,
  127. .cntl = CNTL_LCDTFT | CNTL_LCDVCOMP(1),
  128. .caps = CLCD_CAP_5551,
  129. .fixedtimings = 1,
  130. .connector = IMPD1_CTRL_DISP_LCD,
  131. .bpp = 16,
  132. .grayscale = 0,
  133. };
  134. #elif PANEL == LTM10C209
  135. #define PANELTYPE ltm10c209
  136. /*
  137. * Untested.
  138. */
  139. static struct clcd_panel ltm10c209 = {
  140. .mode = {
  141. .name = "LTM10C209",
  142. .refresh = 0,
  143. .xres = 640,
  144. .yres = 480,
  145. .pixclock = 40000,
  146. .left_margin = 20,
  147. .right_margin = 20,
  148. .upper_margin = 19,
  149. .lower_margin = 19,
  150. .hsync_len = 20,
  151. .vsync_len = 10,
  152. .sync = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
  153. .vmode = FB_VMODE_NONINTERLACED,
  154. },
  155. .width = -1,
  156. .height = -1,
  157. .tim2 = TIM2_BCD,
  158. .cntl = CNTL_LCDTFT | CNTL_LCDVCOMP(1),
  159. .caps = CLCD_CAP_5551,
  160. .fixedtimings = 1,
  161. .connector = IMPD1_CTRL_DISP_LCD,
  162. .bpp = 16,
  163. .grayscale = 0,
  164. };
  165. #endif
  166. /*
  167. * Disable all display connectors on the interface module.
  168. */
  169. static void impd1fb_clcd_disable(struct clcd_fb *fb)
  170. {
  171. impd1_tweak_control(fb->dev->dev.parent, IMPD1_CTRL_DISP_MASK, 0);
  172. }
  173. /*
  174. * Enable the relevant connector on the interface module.
  175. */
  176. static void impd1fb_clcd_enable(struct clcd_fb *fb)
  177. {
  178. impd1_tweak_control(fb->dev->dev.parent, IMPD1_CTRL_DISP_MASK,
  179. fb->panel->connector | IMPD1_CTRL_DISP_ENABLE);
  180. }
  181. static int impd1fb_clcd_setup(struct clcd_fb *fb)
  182. {
  183. unsigned long framebase = fb->dev->res.start + 0x01000000;
  184. unsigned long framesize = SZ_1M;
  185. int ret = 0;
  186. fb->panel = &PANELTYPE;
  187. if (!request_mem_region(framebase, framesize, "clcd framebuffer")) {
  188. printk(KERN_ERR "IM-PD1: unable to reserve framebuffer\n");
  189. return -EBUSY;
  190. }
  191. fb->fb.screen_base = ioremap(framebase, framesize);
  192. if (!fb->fb.screen_base) {
  193. printk(KERN_ERR "IM-PD1: unable to map framebuffer\n");
  194. ret = -ENOMEM;
  195. goto free_buffer;
  196. }
  197. fb->fb.fix.smem_start = framebase;
  198. fb->fb.fix.smem_len = framesize;
  199. return 0;
  200. free_buffer:
  201. release_mem_region(framebase, framesize);
  202. return ret;
  203. }
  204. static int impd1fb_clcd_mmap(struct clcd_fb *fb, struct vm_area_struct *vma)
  205. {
  206. unsigned long start, size;
  207. start = vma->vm_pgoff + (fb->fb.fix.smem_start >> PAGE_SHIFT);
  208. size = vma->vm_end - vma->vm_start;
  209. return remap_pfn_range(vma, vma->vm_start, start, size,
  210. vma->vm_page_prot);
  211. }
  212. static void impd1fb_clcd_remove(struct clcd_fb *fb)
  213. {
  214. iounmap(fb->fb.screen_base);
  215. release_mem_region(fb->fb.fix.smem_start, fb->fb.fix.smem_len);
  216. }
  217. static struct clcd_board impd1_clcd_data = {
  218. .name = "IM-PD/1",
  219. .caps = CLCD_CAP_5551 | CLCD_CAP_888,
  220. .check = clcdfb_check,
  221. .decode = clcdfb_decode,
  222. .disable = impd1fb_clcd_disable,
  223. .enable = impd1fb_clcd_enable,
  224. .setup = impd1fb_clcd_setup,
  225. .mmap = impd1fb_clcd_mmap,
  226. .remove = impd1fb_clcd_remove,
  227. };
  228. struct impd1_device {
  229. unsigned long offset;
  230. unsigned int irq[2];
  231. unsigned int id;
  232. void *platform_data;
  233. };
  234. static struct impd1_device impd1_devs[] = {
  235. {
  236. .offset = 0x03000000,
  237. .id = 0x00041190,
  238. }, {
  239. .offset = 0x00100000,
  240. .irq = { 1 },
  241. .id = 0x00141011,
  242. }, {
  243. .offset = 0x00200000,
  244. .irq = { 2 },
  245. .id = 0x00141011,
  246. }, {
  247. .offset = 0x00300000,
  248. .irq = { 3 },
  249. .id = 0x00041022,
  250. }, {
  251. .offset = 0x00400000,
  252. .irq = { 4 },
  253. .id = 0x00041061,
  254. }, {
  255. .offset = 0x00500000,
  256. .irq = { 5 },
  257. .id = 0x00041061,
  258. }, {
  259. .offset = 0x00600000,
  260. .irq = { 6 },
  261. .id = 0x00041130,
  262. }, {
  263. .offset = 0x00700000,
  264. .irq = { 7, 8 },
  265. .id = 0x00041181,
  266. }, {
  267. .offset = 0x00800000,
  268. .irq = { 9 },
  269. .id = 0x00041041,
  270. }, {
  271. .offset = 0x01000000,
  272. .irq = { 11 },
  273. .id = 0x00041110,
  274. .platform_data = &impd1_clcd_data,
  275. }
  276. };
  277. static int impd1_probe(struct lm_device *dev)
  278. {
  279. struct impd1_module *impd1;
  280. int i, ret;
  281. if (dev->id != module_id)
  282. return -EINVAL;
  283. if (!request_mem_region(dev->resource.start, SZ_4K, "LM registers"))
  284. return -EBUSY;
  285. impd1 = kzalloc(sizeof(struct impd1_module), GFP_KERNEL);
  286. if (!impd1) {
  287. ret = -ENOMEM;
  288. goto release_lm;
  289. }
  290. impd1->base = ioremap(dev->resource.start, SZ_4K);
  291. if (!impd1->base) {
  292. ret = -ENOMEM;
  293. goto free_impd1;
  294. }
  295. lm_set_drvdata(dev, impd1);
  296. printk("IM-PD1 found at 0x%08lx\n",
  297. (unsigned long)dev->resource.start);
  298. integrator_impd1_clk_init(impd1->base, dev->id);
  299. for (i = 0; i < ARRAY_SIZE(impd1_devs); i++) {
  300. struct impd1_device *idev = impd1_devs + i;
  301. struct amba_device *d;
  302. unsigned long pc_base;
  303. char devname[32];
  304. pc_base = dev->resource.start + idev->offset;
  305. snprintf(devname, 32, "lm%x:%5.5lx", dev->id, idev->offset >> 12);
  306. d = amba_ahb_device_add_res(&dev->dev, devname, pc_base, SZ_4K,
  307. dev->irq, dev->irq,
  308. idev->platform_data, idev->id,
  309. &dev->resource);
  310. if (IS_ERR(d)) {
  311. dev_err(&dev->dev, "unable to register device: %ld\n", PTR_ERR(d));
  312. continue;
  313. }
  314. }
  315. return 0;
  316. free_impd1:
  317. if (impd1 && impd1->base)
  318. iounmap(impd1->base);
  319. kfree(impd1);
  320. release_lm:
  321. release_mem_region(dev->resource.start, SZ_4K);
  322. return ret;
  323. }
  324. static int impd1_remove_one(struct device *dev, void *data)
  325. {
  326. device_unregister(dev);
  327. return 0;
  328. }
  329. static void impd1_remove(struct lm_device *dev)
  330. {
  331. struct impd1_module *impd1 = lm_get_drvdata(dev);
  332. device_for_each_child(&dev->dev, NULL, impd1_remove_one);
  333. integrator_impd1_clk_exit(dev->id);
  334. lm_set_drvdata(dev, NULL);
  335. iounmap(impd1->base);
  336. kfree(impd1);
  337. release_mem_region(dev->resource.start, SZ_4K);
  338. }
  339. static struct lm_driver impd1_driver = {
  340. .drv = {
  341. .name = "impd1",
  342. },
  343. .probe = impd1_probe,
  344. .remove = impd1_remove,
  345. };
  346. static int __init impd1_init(void)
  347. {
  348. return lm_driver_register(&impd1_driver);
  349. }
  350. static void __exit impd1_exit(void)
  351. {
  352. lm_driver_unregister(&impd1_driver);
  353. }
  354. module_init(impd1_init);
  355. module_exit(impd1_exit);
  356. MODULE_LICENSE("GPL");
  357. MODULE_DESCRIPTION("Integrator/IM-PD1 logic module core driver");
  358. MODULE_AUTHOR("Deep Blue Solutions Ltd");