fsl_diu.c 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470
  1. /*-
  2. * Copyright (c) 2016 Justin Hibbits
  3. * All rights reserved.
  4. *
  5. * Redistribution and use in source and binary forms, with or without
  6. * modification, are permitted provided that the following conditions
  7. * are met:
  8. * 1. Redistributions of source code must retain the above copyright
  9. * notice, this list of conditions and the following disclaimer.
  10. * 2. Redistributions in binary form must reproduce the above copyright
  11. * notice, this list of conditions and the following disclaimer in the
  12. * documentation and/or other materials provided with the distribution.
  13. *
  14. * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
  15. * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  16. * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  17. * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
  18. * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  19. * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  20. * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  21. * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  22. * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  23. * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  24. * SUCH DAMAGE.
  25. */
  26. #include <sys/cdefs.h>
  27. __FBSDID("$FreeBSD$");
  28. #include <sys/param.h>
  29. #include <sys/systm.h>
  30. #include <sys/bus.h>
  31. #include <sys/endian.h>
  32. #include <sys/kernel.h>
  33. #include <sys/module.h>
  34. #include <sys/malloc.h>
  35. #include <sys/rman.h>
  36. #include <sys/fbio.h>
  37. #include <sys/consio.h>
  38. #include <vm/vm.h>
  39. #include <vm/pmap.h>
  40. #include <dev/fdt/fdt_common.h>
  41. #include <dev/ofw/openfirm.h>
  42. #include <dev/ofw/ofw_bus.h>
  43. #include <dev/ofw/ofw_bus_subr.h>
  44. #include <dev/videomode/videomode.h>
  45. #include <dev/videomode/edidvar.h>
  46. #include <dev/vt/vt.h>
  47. #include <dev/vt/colors/vt_termcolors.h>
  48. #include <powerpc/mpc85xx/mpc85xx.h>
  49. #include <machine/bus.h>
  50. #include <machine/cpu.h>
  51. #include "fb_if.h"
  52. #define DIU_DESC_1 0x000 /* Plane1 Area Descriptor Pointer Register */
  53. #define DIU_DESC_2 0x004 /* Plane2 Area Descriptor Pointer Register */
  54. #define DIU_DESC_3 0x008 /* Plane3 Area Descriptor Pointer Register */
  55. #define DIU_GAMMA 0x00C /* Gamma Register */
  56. #define DIU_PALETTE 0x010 /* Palette Register */
  57. #define DIU_CURSOR 0x014 /* Cursor Register */
  58. #define DIU_CURS_POS 0x018 /* Cursor Position Register */
  59. #define CURSOR_Y_SHIFT 16
  60. #define CURSOR_X_SHIFT 0
  61. #define DIU_DIU_MODE 0x01C /* DIU4 Mode */
  62. #define DIU_MODE_M 0x7
  63. #define DIU_MODE_S 0
  64. #define DIU_MODE_NORMAL 0x1
  65. #define DIU_MODE_2 0x2
  66. #define DIU_MODE_3 0x3
  67. #define DIU_MODE_COLBAR 0x4
  68. #define DIU_BGND 0x020 /* Background */
  69. #define DIU_BGND_WB 0x024 /* Background Color in write back Mode Register */
  70. #define DIU_DISP_SIZE 0x028 /* Display Size */
  71. #define DELTA_Y_S 16
  72. #define DELTA_X_S 0
  73. #define DIU_WB_SIZE 0x02C /* Write back Plane Size Register */
  74. #define DELTA_Y_WB_S 16
  75. #define DELTA_X_WB_S 0
  76. #define DIU_WB_MEM_ADDR 0x030 /* Address to Store the write back Plane Register */
  77. #define DIU_HSYN_PARA 0x034 /* Horizontal Sync Parameter */
  78. #define BP_H_SHIFT 22
  79. #define PW_H_SHIFT 11
  80. #define FP_H_SHIFT 0
  81. #define DIU_VSYN_PARA 0x038 /* Vertical Sync Parameter */
  82. #define BP_V_SHIFT 22
  83. #define PW_V_SHIFT 11
  84. #define FP_V_SHIFT 0
  85. #define DIU_SYNPOL 0x03C /* Synchronize Polarity */
  86. #define BP_VS (1 << 4)
  87. #define BP_HS (1 << 3)
  88. #define INV_CS (1 << 2)
  89. #define INV_VS (1 << 1)
  90. #define INV_HS (1 << 0)
  91. #define INV_PDI_VS (1 << 8) /* Polarity of PDI input VSYNC. */
  92. #define INV_PDI_HS (1 << 9) /* Polarity of PDI input HSYNC. */
  93. #define INV_PDI_DE (1 << 10) /* Polarity of PDI input DE. */
  94. #define DIU_THRESHOLD 0x040 /* Threshold */
  95. #define LS_BF_VS_SHIFT 16
  96. #define OUT_BUF_LOW_SHIFT 0
  97. #define DIU_INT_STATUS 0x044 /* Interrupt Status */
  98. #define DIU_INT_MASK 0x048 /* Interrupt Mask */
  99. #define DIU_COLBAR_1 0x04C /* COLBAR_1 */
  100. #define DIU_COLORBARn_R(x) ((x & 0xff) << 16)
  101. #define DIU_COLORBARn_G(x) ((x & 0xff) << 8)
  102. #define DIU_COLORBARn_B(x) ((x & 0xff) << 0)
  103. #define DIU_COLBAR_2 0x050 /* COLBAR_2 */
  104. #define DIU_COLBAR_3 0x054 /* COLBAR_3 */
  105. #define DIU_COLBAR_4 0x058 /* COLBAR_4 */
  106. #define DIU_COLBAR_5 0x05c /* COLBAR_5 */
  107. #define DIU_COLBAR_6 0x060 /* COLBAR_6 */
  108. #define DIU_COLBAR_7 0x064 /* COLBAR_7 */
  109. #define DIU_COLBAR_8 0x068 /* COLBAR_8 */
  110. #define DIU_FILLING 0x06C /* Filling Register */
  111. #define DIU_PLUT 0x070 /* Priority Look Up Table Register */
  112. /* Control Descriptor */
  113. #define DIU_CTRLDESCL(n, m) 0x200 + (0x40 * n) + 0x4 * (m - 1)
  114. #define DIU_CTRLDESCLn_1(n) DIU_CTRLDESCL(n, 1)
  115. #define DIU_CTRLDESCLn_2(n) DIU_CTRLDESCL(n, 2)
  116. #define DIU_CTRLDESCLn_3(n) DIU_CTRLDESCL(n, 3)
  117. #define TRANS_SHIFT 20
  118. #define DIU_CTRLDESCLn_4(n) DIU_CTRLDESCL(n, 4)
  119. #define BPP_MASK 0xf /* Bit per pixel Mask */
  120. #define BPP_SHIFT 16 /* Bit per pixel Shift */
  121. #define BPP24 0x5
  122. #define EN_LAYER (1 << 31) /* Enable the layer */
  123. #define DIU_CTRLDESCLn_5(n) DIU_CTRLDESCL(n, 5)
  124. #define DIU_CTRLDESCLn_6(n) DIU_CTRLDESCL(n, 6)
  125. #define DIU_CTRLDESCLn_7(n) DIU_CTRLDESCL(n, 7)
  126. #define DIU_CTRLDESCLn_8(n) DIU_CTRLDESCL(n, 8)
  127. #define DIU_CTRLDESCLn_9(n) DIU_CTRLDESCL(n, 9)
  128. #define NUM_LAYERS 1
  129. struct panel_info {
  130. uint32_t panel_width;
  131. uint32_t panel_height;
  132. uint32_t panel_hbp;
  133. uint32_t panel_hpw;
  134. uint32_t panel_hfp;
  135. uint32_t panel_vbp;
  136. uint32_t panel_vpw;
  137. uint32_t panel_vfp;
  138. uint32_t panel_freq;
  139. uint32_t clk_div;
  140. };
  141. struct diu_area_descriptor {
  142. uint32_t pixel_format;
  143. uint32_t bitmap_address;
  144. uint32_t source_size;
  145. uint32_t aoi_size;
  146. uint32_t aoi_offset;
  147. uint32_t display_offset;
  148. uint32_t chroma_key_max;
  149. uint32_t chroma_key_min;
  150. uint32_t next_ad_addr;
  151. } __aligned(32);
  152. struct diu_softc {
  153. struct resource *res[2];
  154. void *ih;
  155. device_t sc_dev;
  156. device_t sc_fbd; /* fbd child */
  157. struct fb_info sc_info;
  158. struct panel_info sc_panel;
  159. struct diu_area_descriptor *sc_planes[3];
  160. uint8_t *sc_gamma;
  161. uint8_t *sc_cursor;
  162. };
  163. static struct resource_spec diu_spec[] = {
  164. { SYS_RES_MEMORY, 0, RF_ACTIVE },
  165. { SYS_RES_IRQ, 0, RF_ACTIVE },
  166. { -1, 0 }
  167. };
  168. static int
  169. diu_probe(device_t dev)
  170. {
  171. if (!ofw_bus_status_okay(dev))
  172. return (ENXIO);
  173. if (!ofw_bus_is_compatible(dev, "fsl,diu"))
  174. return (ENXIO);
  175. device_set_desc(dev, "Freescale Display Interface Unit");
  176. return (BUS_PROBE_DEFAULT);
  177. }
  178. static void
  179. diu_intr(void *arg)
  180. {
  181. struct diu_softc *sc;
  182. int reg;
  183. sc = arg;
  184. /* Ack interrupts */
  185. reg = bus_read_4(sc->res[0], DIU_INT_STATUS);
  186. bus_write_4(sc->res[0], DIU_INT_STATUS, reg);
  187. /* TODO interrupt handler */
  188. }
  189. static int
  190. diu_set_pxclk(device_t dev, unsigned int freq)
  191. {
  192. phandle_t node;
  193. unsigned long bus_freq;
  194. uint32_t pxclk_set;
  195. uint32_t clkdvd;
  196. node = ofw_bus_get_node(device_get_parent(dev));
  197. if ((bus_freq = mpc85xx_get_platform_clock()) <= 0) {
  198. device_printf(dev, "Unable to get bus frequency\n");
  199. return (ENXIO);
  200. }
  201. /* freq is in kHz */
  202. freq *= 1000;
  203. /* adding freq/2 to round-to-closest */
  204. pxclk_set = min(max((bus_freq + freq/2) / freq, 2), 255) << 16;
  205. pxclk_set |= OCP85XX_CLKDVDR_PXCKEN;
  206. clkdvd = ccsr_read4(OCP85XX_CLKDVDR);
  207. clkdvd &= ~(OCP85XX_CLKDVDR_PXCKEN | OCP85XX_CLKDVDR_PXCKINV |
  208. OCP85XX_CLKDVDR_PXCLK_MASK);
  209. ccsr_write4(OCP85XX_CLKDVDR, clkdvd);
  210. ccsr_write4(OCP85XX_CLKDVDR, clkdvd | pxclk_set);
  211. return (0);
  212. }
  213. static int
  214. diu_init(struct diu_softc *sc)
  215. {
  216. struct panel_info *panel;
  217. int reg;
  218. panel = &sc->sc_panel;
  219. /* Temporarily disable the DIU while configuring */
  220. reg = bus_read_4(sc->res[0], DIU_DIU_MODE);
  221. reg &= ~(DIU_MODE_M << DIU_MODE_S);
  222. bus_write_4(sc->res[0], DIU_DIU_MODE, reg);
  223. if (diu_set_pxclk(sc->sc_dev, panel->panel_freq) < 0) {
  224. return (ENXIO);
  225. }
  226. /* Configure DIU */
  227. /* Need to set these somehow later... */
  228. bus_write_4(sc->res[0], DIU_GAMMA, vtophys(sc->sc_gamma));
  229. bus_write_4(sc->res[0], DIU_CURSOR, vtophys(sc->sc_cursor));
  230. bus_write_4(sc->res[0], DIU_CURS_POS, 0);
  231. reg = ((sc->sc_info.fb_height) << DELTA_Y_S);
  232. reg |= sc->sc_info.fb_width;
  233. bus_write_4(sc->res[0], DIU_DISP_SIZE, reg);
  234. reg = (panel->panel_hbp << BP_H_SHIFT);
  235. reg |= (panel->panel_hpw << PW_H_SHIFT);
  236. reg |= (panel->panel_hfp << FP_H_SHIFT);
  237. bus_write_4(sc->res[0], DIU_HSYN_PARA, reg);
  238. reg = (panel->panel_vbp << BP_V_SHIFT);
  239. reg |= (panel->panel_vpw << PW_V_SHIFT);
  240. reg |= (panel->panel_vfp << FP_V_SHIFT);
  241. bus_write_4(sc->res[0], DIU_VSYN_PARA, reg);
  242. bus_write_4(sc->res[0], DIU_BGND, 0);
  243. /* Mask all the interrupts */
  244. bus_write_4(sc->res[0], DIU_INT_MASK, 0x3f);
  245. /* Reset all layers */
  246. sc->sc_planes[0] = contigmalloc(sizeof(struct diu_area_descriptor),
  247. M_DEVBUF, M_ZERO, 0, BUS_SPACE_MAXADDR_32BIT, 32, 0);
  248. bus_write_4(sc->res[0], DIU_DESC_1, vtophys(sc->sc_planes[0]));
  249. bus_write_4(sc->res[0], DIU_DESC_2, 0);
  250. bus_write_4(sc->res[0], DIU_DESC_3, 0);
  251. /* Setup first plane */
  252. /* Area descriptor fields are little endian, so byte swap. */
  253. /* Word 0: Pixel format */
  254. /* Set to 8:8:8:8 ARGB, 4 bytes per pixel, no flip. */
  255. #define MAKE_PXLFMT(as,rs,gs,bs,a,r,g,b,f,s) \
  256. htole32((as << (4 * a)) | (rs << 4 * r) | \
  257. (gs << 4 * g) | (bs << 4 * b) | \
  258. (f << 28) | (s << 16) | \
  259. (a << 25) | (r << 19) | \
  260. (g << 21) | (b << 24))
  261. reg = MAKE_PXLFMT(8, 8, 8, 8, 3, 2, 1, 0, 1, 3);
  262. sc->sc_planes[0]->pixel_format = reg;
  263. /* Word 1: Bitmap address */
  264. sc->sc_planes[0]->bitmap_address = htole32(sc->sc_info.fb_pbase);
  265. /* Word 2: Source size/global alpha */
  266. reg = (sc->sc_info.fb_width | (sc->sc_info.fb_height << 12));
  267. sc->sc_planes[0]->source_size = htole32(reg);
  268. /* Word 3: AOI Size */
  269. reg = (sc->sc_info.fb_width | (sc->sc_info.fb_height << 16));
  270. sc->sc_planes[0]->aoi_size = htole32(reg);
  271. /* Word 4: AOI Offset */
  272. sc->sc_planes[0]->aoi_offset = 0;
  273. /* Word 5: Display offset */
  274. sc->sc_planes[0]->display_offset = 0;
  275. /* Word 6: Chroma key max */
  276. sc->sc_planes[0]->chroma_key_max = 0;
  277. /* Word 7: Chroma key min */
  278. reg = 255 << 16 | 255 << 8 | 255;
  279. sc->sc_planes[0]->chroma_key_min = htole32(reg);
  280. /* Word 8: Next AD */
  281. sc->sc_planes[0]->next_ad_addr = 0;
  282. /* TODO: derive this from the panel size */
  283. bus_write_4(sc->res[0], DIU_PLUT, 0x1f5f666);
  284. /* Enable DIU in normal mode */
  285. reg = bus_read_4(sc->res[0], DIU_DIU_MODE);
  286. reg &= ~(DIU_MODE_M << DIU_MODE_S);
  287. reg |= (DIU_MODE_NORMAL << DIU_MODE_S);
  288. bus_write_4(sc->res[0], DIU_DIU_MODE, reg);
  289. return (0);
  290. }
  291. static int
  292. diu_attach(device_t dev)
  293. {
  294. struct edid_info edid;
  295. struct diu_softc *sc;
  296. const struct videomode *videomode;
  297. void *edid_cells;
  298. const char *vm_name;
  299. phandle_t node;
  300. int h, r, w;
  301. int err, i;
  302. sc = device_get_softc(dev);
  303. sc->sc_dev = dev;
  304. if (bus_alloc_resources(dev, diu_spec, sc->res)) {
  305. device_printf(dev, "could not allocate resources\n");
  306. return (ENXIO);
  307. }
  308. node = ofw_bus_get_node(dev);
  309. /* Setup interrupt handler */
  310. err = bus_setup_intr(dev, sc->res[1], INTR_TYPE_BIO | INTR_MPSAFE,
  311. NULL, diu_intr, sc, &sc->ih);
  312. if (err) {
  313. device_printf(dev, "Unable to alloc interrupt resource.\n");
  314. return (ENXIO);
  315. }
  316. /* TODO: Eventually, allow EDID to be dynamically provided. */
  317. if (OF_getprop_alloc(node, "edid", &edid_cells) <= 0) {
  318. /* Get a resource hint: hint.fb.N.mode */
  319. if (resource_string_value(device_get_name(dev),
  320. device_get_unit(dev), "mode", &vm_name) != 0) {
  321. device_printf(dev,
  322. "No EDID data and no video-mode env set\n");
  323. return (ENXIO);
  324. }
  325. }
  326. if (edid_cells != NULL) {
  327. if (edid_parse(edid_cells, &edid) != 0) {
  328. device_printf(dev, "Error parsing EDID\n");
  329. OF_prop_free(edid_cells);
  330. return (ENXIO);
  331. }
  332. videomode = edid.edid_preferred_mode;
  333. } else {
  334. /* Parse video-mode kenv variable. */
  335. if ((err = sscanf(vm_name, "%dx%d@%d", &w, &h, &r)) != 3) {
  336. device_printf(dev,
  337. "Cannot parse video mode: %s\n", vm_name);
  338. return (ENXIO);
  339. }
  340. videomode = pick_mode_by_ref(w, h, r);
  341. if (videomode == NULL) {
  342. device_printf(dev,
  343. "Cannot find mode for %dx%d@%d", w, h, r);
  344. return (ENXIO);
  345. }
  346. }
  347. sc->sc_panel.panel_width = videomode->hdisplay;
  348. sc->sc_panel.panel_height = videomode->vdisplay;
  349. sc->sc_panel.panel_hbp = videomode->hsync_start - videomode->hdisplay;
  350. sc->sc_panel.panel_hfp = videomode->htotal - videomode->hsync_end;
  351. sc->sc_panel.panel_hpw = videomode->hsync_end - videomode->hsync_start;
  352. sc->sc_panel.panel_vbp = videomode->vsync_start - videomode->vdisplay;
  353. sc->sc_panel.panel_vfp = videomode->vtotal - videomode->vsync_end;
  354. sc->sc_panel.panel_vpw = videomode->vsync_end - videomode->vsync_start;
  355. sc->sc_panel.panel_freq = videomode->dot_clock;
  356. sc->sc_info.fb_width = sc->sc_panel.panel_width;
  357. sc->sc_info.fb_height = sc->sc_panel.panel_height;
  358. sc->sc_info.fb_stride = sc->sc_info.fb_width * 4;
  359. sc->sc_info.fb_bpp = sc->sc_info.fb_depth = 32;
  360. sc->sc_info.fb_size = sc->sc_info.fb_height * sc->sc_info.fb_stride;
  361. sc->sc_info.fb_vbase = (intptr_t)contigmalloc(sc->sc_info.fb_size,
  362. M_DEVBUF, M_ZERO, 0, BUS_SPACE_MAXADDR_32BIT, PAGE_SIZE, 0);
  363. sc->sc_info.fb_pbase = (intptr_t)vtophys(sc->sc_info.fb_vbase);
  364. sc->sc_info.fb_flags = FB_FLAG_MEMATTR;
  365. sc->sc_info.fb_memattr = VM_MEMATTR_DEFAULT;
  366. /* Gamma table is 3 consecutive segments of 256 bytes. */
  367. sc->sc_gamma = contigmalloc(3 * 256, M_DEVBUF, 0, 0,
  368. BUS_SPACE_MAXADDR_32BIT, PAGE_SIZE, 0);
  369. /* Initialize gamma to default */
  370. for (i = 0; i < 3 * 256; i++)
  371. sc->sc_gamma[i] = (i % 256);
  372. /* Cursor format is 32x32x16bpp */
  373. sc->sc_cursor = contigmalloc(32 * 32 * 2, M_DEVBUF, M_ZERO, 0,
  374. BUS_SPACE_MAXADDR_32BIT, PAGE_SIZE, 0);
  375. diu_init(sc);
  376. sc->sc_info.fb_name = device_get_nameunit(dev);
  377. /* Ask newbus to attach framebuffer device to me. */
  378. sc->sc_fbd = device_add_child(dev, "fbd", device_get_unit(dev));
  379. if (sc->sc_fbd == NULL)
  380. device_printf(dev, "Can't attach fbd device\n");
  381. if ((err = device_probe_and_attach(sc->sc_fbd)) != 0) {
  382. device_printf(dev, "Failed to attach fbd device: %d\n", err);
  383. }
  384. return (0);
  385. }
  386. static struct fb_info *
  387. diu_fb_getinfo(device_t dev)
  388. {
  389. struct diu_softc *sc = device_get_softc(dev);
  390. return (&sc->sc_info);
  391. }
  392. static device_method_t diu_methods[] = {
  393. DEVMETHOD(device_probe, diu_probe),
  394. DEVMETHOD(device_attach, diu_attach),
  395. /* Framebuffer service methods */
  396. DEVMETHOD(fb_getinfo, diu_fb_getinfo),
  397. { 0, 0 }
  398. };
  399. static driver_t diu_driver = {
  400. "fb",
  401. diu_methods,
  402. sizeof(struct diu_softc),
  403. };
  404. static devclass_t diu_devclass;
  405. DRIVER_MODULE(fb, simplebus, diu_driver, diu_devclass, 0, 0);