pl111_versatile.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404
  1. #include <linux/amba/clcd-regs.h>
  2. #include <linux/device.h>
  3. #include <linux/of.h>
  4. #include <linux/of_platform.h>
  5. #include <linux/regmap.h>
  6. #include <linux/mfd/syscon.h>
  7. #include <linux/bitops.h>
  8. #include <linux/module.h>
  9. #include <drm/drmP.h>
  10. #include "pl111_versatile.h"
  11. #include "pl111_vexpress.h"
  12. #include "pl111_drm.h"
  13. static struct regmap *versatile_syscon_map;
  14. /*
  15. * We detect the different syscon types from the compatible strings.
  16. */
  17. enum versatile_clcd {
  18. INTEGRATOR_CLCD_CM,
  19. VERSATILE_CLCD,
  20. REALVIEW_CLCD_EB,
  21. REALVIEW_CLCD_PB1176,
  22. REALVIEW_CLCD_PB11MP,
  23. REALVIEW_CLCD_PBA8,
  24. REALVIEW_CLCD_PBX,
  25. VEXPRESS_CLCD_V2M,
  26. };
  27. static const struct of_device_id versatile_clcd_of_match[] = {
  28. {
  29. .compatible = "arm,core-module-integrator",
  30. .data = (void *)INTEGRATOR_CLCD_CM,
  31. },
  32. {
  33. .compatible = "arm,versatile-sysreg",
  34. .data = (void *)VERSATILE_CLCD,
  35. },
  36. {
  37. .compatible = "arm,realview-eb-syscon",
  38. .data = (void *)REALVIEW_CLCD_EB,
  39. },
  40. {
  41. .compatible = "arm,realview-pb1176-syscon",
  42. .data = (void *)REALVIEW_CLCD_PB1176,
  43. },
  44. {
  45. .compatible = "arm,realview-pb11mp-syscon",
  46. .data = (void *)REALVIEW_CLCD_PB11MP,
  47. },
  48. {
  49. .compatible = "arm,realview-pba8-syscon",
  50. .data = (void *)REALVIEW_CLCD_PBA8,
  51. },
  52. {
  53. .compatible = "arm,realview-pbx-syscon",
  54. .data = (void *)REALVIEW_CLCD_PBX,
  55. },
  56. {
  57. .compatible = "arm,vexpress-muxfpga",
  58. .data = (void *)VEXPRESS_CLCD_V2M,
  59. },
  60. {},
  61. };
  62. /*
  63. * Core module CLCD control on the Integrator/CP, bits
  64. * 8 thru 19 of the CM_CONTROL register controls a bunch
  65. * of CLCD settings.
  66. */
  67. #define INTEGRATOR_HDR_CTRL_OFFSET 0x0C
  68. #define INTEGRATOR_CLCD_LCDBIASEN BIT(8)
  69. #define INTEGRATOR_CLCD_LCDBIASUP BIT(9)
  70. #define INTEGRATOR_CLCD_LCDBIASDN BIT(10)
  71. /* Bits 11,12,13 controls the LCD or VGA bridge type */
  72. #define INTEGRATOR_CLCD_LCDMUX_LCD24 BIT(11)
  73. #define INTEGRATOR_CLCD_LCDMUX_SHARP (BIT(11)|BIT(12))
  74. #define INTEGRATOR_CLCD_LCDMUX_VGA555 BIT(13)
  75. #define INTEGRATOR_CLCD_LCDMUX_VGA24 (BIT(11)|BIT(12)|BIT(13))
  76. #define INTEGRATOR_CLCD_LCD0_EN BIT(14)
  77. #define INTEGRATOR_CLCD_LCD1_EN BIT(15)
  78. /* R/L flip on Sharp */
  79. #define INTEGRATOR_CLCD_LCD_STATIC1 BIT(16)
  80. /* U/D flip on Sharp */
  81. #define INTEGRATOR_CLCD_LCD_STATIC2 BIT(17)
  82. /* No connection on Sharp */
  83. #define INTEGRATOR_CLCD_LCD_STATIC BIT(18)
  84. /* 0 = 24bit VGA, 1 = 18bit VGA */
  85. #define INTEGRATOR_CLCD_LCD_N24BITEN BIT(19)
  86. #define INTEGRATOR_CLCD_MASK GENMASK(19, 8)
  87. static void pl111_integrator_enable(struct drm_device *drm, u32 format)
  88. {
  89. u32 val;
  90. dev_info(drm->dev, "enable Integrator CLCD connectors\n");
  91. /* FIXME: really needed? */
  92. val = INTEGRATOR_CLCD_LCD_STATIC1 | INTEGRATOR_CLCD_LCD_STATIC2 |
  93. INTEGRATOR_CLCD_LCD0_EN | INTEGRATOR_CLCD_LCD1_EN;
  94. switch (format) {
  95. case DRM_FORMAT_XBGR8888:
  96. case DRM_FORMAT_XRGB8888:
  97. /* 24bit formats */
  98. val |= INTEGRATOR_CLCD_LCDMUX_VGA24;
  99. break;
  100. case DRM_FORMAT_XBGR1555:
  101. case DRM_FORMAT_XRGB1555:
  102. /* Pseudocolor, RGB555, BGR555 */
  103. val |= INTEGRATOR_CLCD_LCDMUX_VGA555;
  104. break;
  105. default:
  106. dev_err(drm->dev, "unhandled format on Integrator 0x%08x\n",
  107. format);
  108. break;
  109. }
  110. regmap_update_bits(versatile_syscon_map,
  111. INTEGRATOR_HDR_CTRL_OFFSET,
  112. INTEGRATOR_CLCD_MASK,
  113. val);
  114. }
  115. /*
  116. * This configuration register in the Versatile and RealView
  117. * family is uniformly present but appears more and more
  118. * unutilized starting with the RealView series.
  119. */
  120. #define SYS_CLCD 0x50
  121. #define SYS_CLCD_MODE_MASK (BIT(0)|BIT(1))
  122. #define SYS_CLCD_MODE_888 0
  123. #define SYS_CLCD_MODE_5551 BIT(0)
  124. #define SYS_CLCD_MODE_565_R_LSB BIT(1)
  125. #define SYS_CLCD_MODE_565_B_LSB (BIT(0)|BIT(1))
  126. #define SYS_CLCD_CONNECTOR_MASK (BIT(2)|BIT(3)|BIT(4)|BIT(5))
  127. #define SYS_CLCD_NLCDIOON BIT(2)
  128. #define SYS_CLCD_VDDPOSSWITCH BIT(3)
  129. #define SYS_CLCD_PWR3V5SWITCH BIT(4)
  130. #define SYS_CLCD_VDDNEGSWITCH BIT(5)
  131. static void pl111_versatile_disable(struct drm_device *drm)
  132. {
  133. dev_info(drm->dev, "disable Versatile CLCD connectors\n");
  134. regmap_update_bits(versatile_syscon_map,
  135. SYS_CLCD,
  136. SYS_CLCD_CONNECTOR_MASK,
  137. 0);
  138. }
  139. static void pl111_versatile_enable(struct drm_device *drm, u32 format)
  140. {
  141. u32 val = 0;
  142. dev_info(drm->dev, "enable Versatile CLCD connectors\n");
  143. switch (format) {
  144. case DRM_FORMAT_ABGR8888:
  145. case DRM_FORMAT_XBGR8888:
  146. case DRM_FORMAT_ARGB8888:
  147. case DRM_FORMAT_XRGB8888:
  148. val |= SYS_CLCD_MODE_888;
  149. break;
  150. case DRM_FORMAT_BGR565:
  151. val |= SYS_CLCD_MODE_565_R_LSB;
  152. break;
  153. case DRM_FORMAT_RGB565:
  154. val |= SYS_CLCD_MODE_565_B_LSB;
  155. break;
  156. case DRM_FORMAT_ABGR1555:
  157. case DRM_FORMAT_XBGR1555:
  158. case DRM_FORMAT_ARGB1555:
  159. case DRM_FORMAT_XRGB1555:
  160. val |= SYS_CLCD_MODE_5551;
  161. break;
  162. default:
  163. dev_err(drm->dev, "unhandled format on Versatile 0x%08x\n",
  164. format);
  165. break;
  166. }
  167. /* Set up the MUX */
  168. regmap_update_bits(versatile_syscon_map,
  169. SYS_CLCD,
  170. SYS_CLCD_MODE_MASK,
  171. val);
  172. /* Then enable the display */
  173. regmap_update_bits(versatile_syscon_map,
  174. SYS_CLCD,
  175. SYS_CLCD_CONNECTOR_MASK,
  176. SYS_CLCD_NLCDIOON | SYS_CLCD_PWR3V5SWITCH);
  177. }
  178. static void pl111_realview_clcd_disable(struct drm_device *drm)
  179. {
  180. dev_info(drm->dev, "disable RealView CLCD connectors\n");
  181. regmap_update_bits(versatile_syscon_map,
  182. SYS_CLCD,
  183. SYS_CLCD_CONNECTOR_MASK,
  184. 0);
  185. }
  186. static void pl111_realview_clcd_enable(struct drm_device *drm, u32 format)
  187. {
  188. dev_info(drm->dev, "enable RealView CLCD connectors\n");
  189. regmap_update_bits(versatile_syscon_map,
  190. SYS_CLCD,
  191. SYS_CLCD_CONNECTOR_MASK,
  192. SYS_CLCD_NLCDIOON | SYS_CLCD_PWR3V5SWITCH);
  193. }
  194. /* PL110 pixel formats for Integrator, vanilla PL110 */
  195. static const u32 pl110_integrator_pixel_formats[] = {
  196. DRM_FORMAT_ABGR8888,
  197. DRM_FORMAT_XBGR8888,
  198. DRM_FORMAT_ARGB8888,
  199. DRM_FORMAT_XRGB8888,
  200. DRM_FORMAT_ABGR1555,
  201. DRM_FORMAT_XBGR1555,
  202. DRM_FORMAT_ARGB1555,
  203. DRM_FORMAT_XRGB1555,
  204. };
  205. /* Extended PL110 pixel formats for Integrator and Versatile */
  206. static const u32 pl110_versatile_pixel_formats[] = {
  207. DRM_FORMAT_ABGR8888,
  208. DRM_FORMAT_XBGR8888,
  209. DRM_FORMAT_ARGB8888,
  210. DRM_FORMAT_XRGB8888,
  211. DRM_FORMAT_BGR565, /* Uses external PLD */
  212. DRM_FORMAT_RGB565, /* Uses external PLD */
  213. DRM_FORMAT_ABGR1555,
  214. DRM_FORMAT_XBGR1555,
  215. DRM_FORMAT_ARGB1555,
  216. DRM_FORMAT_XRGB1555,
  217. };
  218. static const u32 pl111_realview_pixel_formats[] = {
  219. DRM_FORMAT_ABGR8888,
  220. DRM_FORMAT_XBGR8888,
  221. DRM_FORMAT_ARGB8888,
  222. DRM_FORMAT_XRGB8888,
  223. DRM_FORMAT_BGR565,
  224. DRM_FORMAT_RGB565,
  225. DRM_FORMAT_ABGR1555,
  226. DRM_FORMAT_XBGR1555,
  227. DRM_FORMAT_ARGB1555,
  228. DRM_FORMAT_XRGB1555,
  229. DRM_FORMAT_ABGR4444,
  230. DRM_FORMAT_XBGR4444,
  231. DRM_FORMAT_ARGB4444,
  232. DRM_FORMAT_XRGB4444,
  233. };
  234. /*
  235. * The Integrator variant is a PL110 with a bunch of broken, or not
  236. * yet implemented features
  237. */
  238. static const struct pl111_variant_data pl110_integrator = {
  239. .name = "PL110 Integrator",
  240. .is_pl110 = true,
  241. .broken_clockdivider = true,
  242. .broken_vblank = true,
  243. .formats = pl110_integrator_pixel_formats,
  244. .nformats = ARRAY_SIZE(pl110_integrator_pixel_formats),
  245. .fb_bpp = 16,
  246. };
  247. /*
  248. * This is the in-between PL110 variant found in the ARM Versatile,
  249. * supporting RGB565/BGR565
  250. */
  251. static const struct pl111_variant_data pl110_versatile = {
  252. .name = "PL110 Versatile",
  253. .is_pl110 = true,
  254. .external_bgr = true,
  255. .formats = pl110_versatile_pixel_formats,
  256. .nformats = ARRAY_SIZE(pl110_versatile_pixel_formats),
  257. .fb_bpp = 16,
  258. };
  259. /*
  260. * RealView PL111 variant, the only real difference from the vanilla
  261. * PL111 is that we select 16bpp framebuffer by default to be able
  262. * to get 1024x768 without saturating the memory bus.
  263. */
  264. static const struct pl111_variant_data pl111_realview = {
  265. .name = "PL111 RealView",
  266. .formats = pl111_realview_pixel_formats,
  267. .nformats = ARRAY_SIZE(pl111_realview_pixel_formats),
  268. .fb_bpp = 16,
  269. };
  270. /*
  271. * Versatile Express PL111 variant, again we just push the maximum
  272. * BPP to 16 to be able to get 1024x768 without saturating the memory
  273. * bus. The clockdivider also seems broken on the Versatile Express.
  274. */
  275. static const struct pl111_variant_data pl111_vexpress = {
  276. .name = "PL111 Versatile Express",
  277. .formats = pl111_realview_pixel_formats,
  278. .nformats = ARRAY_SIZE(pl111_realview_pixel_formats),
  279. .fb_bpp = 16,
  280. .broken_clockdivider = true,
  281. };
  282. int pl111_versatile_init(struct device *dev, struct pl111_drm_dev_private *priv)
  283. {
  284. const struct of_device_id *clcd_id;
  285. enum versatile_clcd versatile_clcd_type;
  286. struct device_node *np;
  287. struct regmap *map;
  288. int ret;
  289. np = of_find_matching_node_and_match(NULL, versatile_clcd_of_match,
  290. &clcd_id);
  291. if (!np) {
  292. /* Non-ARM reference designs, just bail out */
  293. return 0;
  294. }
  295. versatile_clcd_type = (enum versatile_clcd)clcd_id->data;
  296. /* Versatile Express special handling */
  297. if (versatile_clcd_type == VEXPRESS_CLCD_V2M) {
  298. struct platform_device *pdev;
  299. /* Registers a driver for the muxfpga */
  300. ret = vexpress_muxfpga_init();
  301. if (ret) {
  302. dev_err(dev, "unable to initialize muxfpga driver\n");
  303. return ret;
  304. }
  305. /* Call into deep Vexpress configuration API */
  306. pdev = of_find_device_by_node(np);
  307. if (!pdev) {
  308. dev_err(dev, "can't find the sysreg device, deferring\n");
  309. return -EPROBE_DEFER;
  310. }
  311. map = dev_get_drvdata(&pdev->dev);
  312. if (!map) {
  313. dev_err(dev, "sysreg has not yet probed\n");
  314. platform_device_put(pdev);
  315. return -EPROBE_DEFER;
  316. }
  317. } else {
  318. map = syscon_node_to_regmap(np);
  319. }
  320. if (IS_ERR(map)) {
  321. dev_err(dev, "no Versatile syscon regmap\n");
  322. return PTR_ERR(map);
  323. }
  324. switch (versatile_clcd_type) {
  325. case INTEGRATOR_CLCD_CM:
  326. versatile_syscon_map = map;
  327. priv->variant = &pl110_integrator;
  328. priv->variant_display_enable = pl111_integrator_enable;
  329. dev_info(dev, "set up callbacks for Integrator PL110\n");
  330. break;
  331. case VERSATILE_CLCD:
  332. versatile_syscon_map = map;
  333. /* This can do RGB565 with external PLD */
  334. priv->variant = &pl110_versatile;
  335. priv->variant_display_enable = pl111_versatile_enable;
  336. priv->variant_display_disable = pl111_versatile_disable;
  337. /*
  338. * The Versatile has a variant halfway between PL110
  339. * and PL111 where these two registers have already been
  340. * swapped.
  341. */
  342. priv->ienb = CLCD_PL111_IENB;
  343. priv->ctrl = CLCD_PL111_CNTL;
  344. dev_info(dev, "set up callbacks for Versatile PL110\n");
  345. break;
  346. case REALVIEW_CLCD_EB:
  347. case REALVIEW_CLCD_PB1176:
  348. case REALVIEW_CLCD_PB11MP:
  349. case REALVIEW_CLCD_PBA8:
  350. case REALVIEW_CLCD_PBX:
  351. versatile_syscon_map = map;
  352. priv->variant = &pl111_realview;
  353. priv->variant_display_enable = pl111_realview_clcd_enable;
  354. priv->variant_display_disable = pl111_realview_clcd_disable;
  355. dev_info(dev, "set up callbacks for RealView PL111\n");
  356. break;
  357. case VEXPRESS_CLCD_V2M:
  358. priv->variant = &pl111_vexpress;
  359. dev_info(dev, "initializing Versatile Express PL111\n");
  360. ret = pl111_vexpress_clcd_init(dev, priv, map);
  361. if (ret)
  362. return ret;
  363. break;
  364. default:
  365. dev_info(dev, "unknown Versatile system controller\n");
  366. break;
  367. }
  368. return 0;
  369. }
  370. EXPORT_SYMBOL_GPL(pl111_versatile_init);