pl111_versatile.c 9.2 KB

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