1 /* $NetBSD: imx51_ipuv3.c,v 1.1 2012/04/17 10:19:57 bsh Exp $ */ 2 3 /* 4 * Copyright (c) 2011, 2012 Genetec Corporation. All rights reserved. 5 * Written by Hashimoto Kenichi for Genetec Corporation. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY GENETEC CORPORATION ``AS IS'' AND 17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 18 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 19 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GENETEC CORPORATION 20 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 24 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 26 * POSSIBILITY OF SUCH DAMAGE. 27 */ 28 29 #include <sys/cdefs.h> 30 __KERNEL_RCSID(0, "$NetBSD: imx51_ipuv3.c,v 1.1 2012/04/17 10:19:57 bsh Exp $"); 31 32 #include <sys/param.h> 33 #include <sys/systm.h> 34 #include <sys/conf.h> 35 #include <sys/uio.h> 36 #include <sys/malloc.h> 37 #include <sys/kernel.h> /* for cold */ 38 39 #include <uvm/uvm_extern.h> 40 41 #include <dev/cons.h> 42 #include <dev/wscons/wsconsio.h> 43 #include <dev/wscons/wsdisplayvar.h> 44 #include <dev/wscons/wscons_callbacks.h> 45 #include <dev/rasops/rasops.h> 46 #include <dev/wsfont/wsfont.h> 47 #include <dev/wscons/wsdisplay_vconsvar.h> 48 49 #include <sys/bus.h> 50 #include <machine/cpu.h> 51 #include <arm/cpufunc.h> 52 53 #include <arm/imx/imx51var.h> 54 #include <arm/imx/imx51reg.h> 55 #include <arm/imx/imx51_ipuv3var.h> 56 #include <arm/imx/imx51_ipuv3reg.h> 57 #include <arm/imx/imx51_ccmvar.h> 58 #include <arm/imx/imx51_ccmreg.h> 59 60 #include "imxccm.h" /* if CCM driver is configured into the kernel */ 61 #include "wsdisplay.h" 62 #include "opt_imx51_ipuv3.h" 63 64 /* 65 * Console variables. These are necessary since console is setup very early, 66 * before devices get attached. 67 */ 68 struct { 69 int is_console; 70 } imx51_ipuv3_console; 71 72 #define IPUV3_READ(ipuv3, module, reg) \ 73 bus_space_read_4((ipuv3)->iot, (ipuv3)->module##_ioh, (reg)) 74 #define IPUV3_WRITE(ipuv3, module, reg, val) \ 75 bus_space_write_4((ipuv3)->iot, (ipuv3)->module##_ioh, (reg), (val)) 76 77 #ifdef IPUV3_DEBUG 78 int ipuv3_debug = IPUV3_DEBUG; 79 #define DPRINTFN(n,x) if (ipuv3_debug>(n)) printf x; else 80 #else 81 #define DPRINTFN(n,x) 82 #endif 83 84 int ipuv3intr(void *); 85 86 static void imx51_ipuv3_initialize(struct imx51_ipuv3_softc *, 87 const struct lcd_panel_geometry *); 88 #if NWSDISPLAY > 0 89 static void imx51_ipuv3_setup_rasops(struct imx51_ipuv3_softc *, 90 struct rasops_info *, struct imx51_wsscreen_descr *, 91 const struct lcd_panel_geometry *); 92 #endif 93 static void imx51_ipuv3_set_idma_param(uint32_t *, uint32_t, uint32_t); 94 95 #if NWSDISPLAY > 0 96 /* 97 * wsdisplay glue 98 */ 99 static struct imx51_wsscreen_descr imx51_ipuv3_stdscreen = { 100 .c = { 101 .name = "std", 102 .ncols = 0, 103 .nrows = 0, 104 .textops = NULL, 105 .fontwidth = 8, 106 .fontheight = 16, 107 .capabilities = WSSCREEN_WSCOLORS | WSSCREEN_HILIT, 108 .modecookie = NULL 109 }, 110 .depth = 16, /* bits per pixel */ 111 .flags = RI_CENTER | RI_FULLCLEAR 112 }; 113 114 static const struct wsscreen_descr *imx51_ipuv3_scr_descr[] = { 115 &imx51_ipuv3_stdscreen.c, 116 }; 117 118 const struct wsscreen_list imx51_ipuv3_screen_list = { 119 sizeof imx51_ipuv3_scr_descr / sizeof imx51_ipuv3_scr_descr[0], 120 imx51_ipuv3_scr_descr 121 }; 122 123 struct wsdisplay_accessops imx51_ipuv3_accessops = { 124 .ioctl = imx51_ipuv3_ioctl, 125 .mmap = imx51_ipuv3_mmap, 126 .alloc_screen = NULL, 127 .free_screen = NULL, 128 .show_screen = NULL, 129 .load_font = NULL, 130 .pollc = NULL, 131 .scroll = NULL 132 }; 133 #endif 134 135 #ifdef IPUV3_DEBUG 136 static void 137 imx51_ipuv3_dump(struct imx51_ipuv3_softc *sc) 138 { 139 int i; 140 141 DPRINTFN(5, ("%s : %d\n", __func__, __LINE__)); 142 143 #define __DUMP(grp, reg) \ 144 DPRINTFN(4, ("%-16s = 0x%08X\n", #reg, IPUV3_READ(sc, grp, IPU_##reg))) 145 146 __DUMP(cm, CM_CONF); 147 __DUMP(cm, CM_DISP_GEN); 148 __DUMP(idmac, IDMAC_CONF); 149 __DUMP(idmac, IDMAC_CH_EN_1); 150 __DUMP(idmac, IDMAC_CH_EN_2); 151 __DUMP(idmac, IDMAC_CH_PRI_1); 152 __DUMP(idmac, IDMAC_CH_PRI_2); 153 __DUMP(idmac, IDMAC_BNDM_EN_1); 154 __DUMP(idmac, IDMAC_BNDM_EN_2); 155 __DUMP(cm, CM_CH_DB_MODE_SEL_0); 156 __DUMP(cm, CM_CH_DB_MODE_SEL_1); 157 __DUMP(dmfc, DMFC_WR_CHAN); 158 __DUMP(dmfc, DMFC_WR_CHAN_DEF); 159 __DUMP(dmfc, DMFC_DP_CHAN); 160 __DUMP(dmfc, DMFC_DP_CHAN_DEF); 161 __DUMP(dmfc, DMFC_IC_CTRL); 162 __DUMP(cm, CM_FS_PROC_FLOW1); 163 __DUMP(cm, CM_FS_PROC_FLOW2); 164 __DUMP(cm, CM_FS_PROC_FLOW3); 165 __DUMP(cm, CM_FS_DISP_FLOW1); 166 __DUMP(dc, DC_DISP_CONF1_0); 167 __DUMP(dc, DC_DISP_CONF2_0); 168 __DUMP(dc, DC_WR_CH_CONF_5); 169 170 printf("*** IPU ***\n"); 171 for (i = 0; i <= 0x17c; i += 4) 172 DPRINTFN(6, ("0x%08X = 0x%08X\n", i, IPUV3_READ(sc, cm, i))); 173 printf("*** IDMAC ***\n"); 174 for (i = 0; i <= 0x104; i += 4) 175 DPRINTFN(6, ("0x%08X = 0x%08X\n", i, IPUV3_READ(sc, idmac, i))); 176 printf("*** CPMEM ***\n"); 177 for (i = 0x5c0; i <= 0x600; i += 4) 178 DPRINTFN(6, ("0x%08X = 0x%08X\n", i, IPUV3_READ(sc, cpmem, i))); 179 180 #undef __DUMP 181 182 } 183 #endif 184 185 static void 186 imx51_ipuv3_enable_display(struct imx51_ipuv3_softc *sc) 187 { 188 uint32_t reg = 0; 189 190 DPRINTFN(5, ("%s : %d\n", __func__, __LINE__)); 191 192 /* enable sub modules */ 193 reg = IPUV3_READ(sc, cm, IPU_CM_CONF); 194 reg |= CM_CONF_DP_EN | 195 CM_CONF_DC_EN | 196 CM_CONF_DMFC_EN | 197 CM_CONF_DI0_EN; 198 IPUV3_WRITE(sc, cm, IPU_CM_CONF, reg); 199 } 200 201 static void 202 imx51_ipuv3_dmfc_init(struct imx51_ipuv3_softc *sc) 203 { 204 DPRINTFN(5, ("%s : %d\n", __func__, __LINE__)); 205 206 /* IC channel is disabled */ 207 IPUV3_WRITE(sc, dmfc, IPU_DMFC_IC_CTRL, 208 IC_IN_PORT_DISABLE); 209 210 IPUV3_WRITE(sc, dmfc, IPU_DMFC_WR_CHAN, 0x00000000); 211 IPUV3_WRITE(sc, dmfc, IPU_DMFC_WR_CHAN_DEF, 0x20202020); 212 IPUV3_WRITE(sc, dmfc, IPU_DMFC_DP_CHAN, 0x00000094); 213 IPUV3_WRITE(sc, dmfc, IPU_DMFC_DP_CHAN_DEF, 0x202020F6); 214 215 IPUV3_WRITE(sc, dmfc, IPU_DMFC_GENERAL1, 216 DCDP_SYNC_PR_ROUNDROBIN); 217 218 #ifdef IPUV3_DEBUG 219 int i; 220 printf("*** DMFC ***\n"); 221 for (i = 0; i <= 0x34; i += 4) 222 printf("0x%08X = 0x%08X\n", i, IPUV3_READ(sc, dmfc, i)); 223 224 printf("%s: DMFC_IC_CTRL 0x%08X\n", __func__, 225 IPUV3_READ(sc, dmfc, IPU_DMFC_IC_CTRL)); 226 printf("%s: IPU_DMFC_WR_CHAN 0x%08X\n", __func__, 227 IPUV3_READ(sc, dmfc, IPU_DMFC_WR_CHAN)); 228 printf("%s: IPU_DMFC_WR_CHAN_DEF 0x%08X\n", __func__, 229 IPUV3_READ(sc, dmfc, IPU_DMFC_WR_CHAN_DEF)); 230 printf("%s: IPU_DMFC_GENERAL1 0x%08X\n", __func__, 231 IPUV3_READ(sc, dmfc, IPU_DMFC_GENERAL1)); 232 #endif 233 } 234 235 static void 236 imx51_ipuv3_dc_map_clear(struct imx51_ipuv3_softc *sc, int map) 237 { 238 DPRINTFN(5, ("%s : %d\n", __func__, __LINE__)); 239 240 uint32_t reg; 241 uint32_t addr; 242 243 addr = IPU_DC_MAP_CONF_PNTR(map / 2); 244 reg = IPUV3_READ(sc, dc, addr); 245 reg &= ~(0xFFFF << (16 * (map & 0x1))); 246 IPUV3_WRITE(sc, dc, addr, reg); 247 } 248 249 static void 250 imx51_ipuv3_dc_map_conf(struct imx51_ipuv3_softc *sc, 251 int map, int byte, int offset, uint8_t mask) 252 { 253 DPRINTFN(5, ("%s : %d\n", __func__, __LINE__)); 254 255 uint32_t reg; 256 uint32_t addr; 257 258 addr = IPU_DC_MAP_CONF_MASK((map * 3 + byte) / 2); 259 reg = IPUV3_READ(sc, dc, addr); 260 reg &= ~(0xFFFF << (16 * ((map * 3 + byte) & 0x1))); 261 reg |= ((offset << 8) | mask) << (16 * ((map * 3 + byte) & 0x1)); 262 IPUV3_WRITE(sc, dc, addr, reg); 263 #ifdef IPUV3_DEBUG 264 printf("%s: addr 0x%08X reg 0x%08X\n", __func__, addr, reg); 265 #endif 266 267 addr = IPU_DC_MAP_CONF_PNTR(map / 2); 268 reg = IPUV3_READ(sc, dc, addr); 269 reg &= ~(0x1F << ((16 * (map & 0x1)) + (5 * byte))); 270 reg |= ((map * 3) + byte) << ((16 * (map & 0x1)) + (5 * byte)); 271 IPUV3_WRITE(sc, dc, addr, reg); 272 #ifdef IPUV3_DEBUG 273 printf("%s: addr 0x%08X reg 0x%08X\n", __func__, addr, reg); 274 #endif 275 } 276 277 static void 278 imx51_ipuv3_dc_template_command(struct imx51_ipuv3_softc *sc, 279 int index, int sync, int gluelogic, int waveform, int mapping, 280 int operand, int opecode, int stop) 281 { 282 DPRINTFN(5, ("%s : %d\n", __func__, __LINE__)); 283 284 uint32_t reg; 285 286 reg = (sync << 0) | 287 (gluelogic << 4) | 288 (waveform << 11) | 289 (mapping << 15) | 290 (operand << 20); 291 IPUV3_WRITE(sc, dctmpl, index * 8, reg); 292 #ifdef IPUV3_DEBUG 293 printf("%s: addr 0x%08X reg 0x%08X\n", __func__, index * 8, reg); 294 #endif 295 reg = (opecode << 0) | 296 (stop << 9); 297 IPUV3_WRITE(sc, dctmpl, index * 8 + 4, reg); 298 #ifdef IPUV3_DEBUG 299 printf("%s: addr 0x%08X reg 0x%08X\n", __func__, index * 8 + 4, reg); 300 #endif 301 } 302 303 static void 304 imx51_ipuv3_set_routine_link(struct imx51_ipuv3_softc *sc, 305 int base, int evt, int addr, int pri) 306 { 307 DPRINTFN(5, ("%s : %d\n", __func__, __LINE__)); 308 309 uint32_t reg; 310 311 reg = IPUV3_READ(sc, dc, IPU_DC_RL(base, evt)); 312 reg &= ~(0xFFFF << (16 * (evt & 0x1))); 313 reg |= ((addr << 8) | pri) << (16 * (evt & 0x1)); 314 IPUV3_WRITE(sc, dc, IPU_DC_RL(base, evt), reg); 315 #ifdef IPUV3_DEBUG 316 printf("%s: event %d addr %d priority %d\n", __func__, 317 evt, addr, pri); 318 printf("%s: %p = 0x%08X\n", __func__, 319 (void *)IPU_DC_RL(base, evt), reg); 320 #endif 321 } 322 323 static void 324 imx51_ipuv3_dc_init(struct imx51_ipuv3_softc *sc) 325 { 326 uint32_t reg; 327 328 DPRINTFN(5, ("%s : %d\n", __func__, __LINE__)); 329 330 imx51_ipuv3_dc_map_clear(sc, 0); 331 imx51_ipuv3_dc_map_conf(sc, 0, 0, 7, 0xff); 332 imx51_ipuv3_dc_map_conf(sc, 0, 1, 15, 0xff); 333 imx51_ipuv3_dc_map_conf(sc, 0, 2, 23, 0xff); 334 imx51_ipuv3_dc_map_clear(sc, 1); 335 imx51_ipuv3_dc_map_conf(sc, 1, 0, 5, 0xfc); 336 imx51_ipuv3_dc_map_conf(sc, 1, 1, 11, 0xfc); 337 imx51_ipuv3_dc_map_conf(sc, 1, 2, 17, 0xfc); 338 imx51_ipuv3_dc_map_clear(sc, 2); 339 imx51_ipuv3_dc_map_conf(sc, 2, 0, 15, 0xff); 340 imx51_ipuv3_dc_map_conf(sc, 2, 1, 23, 0xff); 341 imx51_ipuv3_dc_map_conf(sc, 2, 2, 7, 0xff); 342 imx51_ipuv3_dc_map_clear(sc, 3); 343 imx51_ipuv3_dc_map_conf(sc, 3, 0, 4, 0xf8); 344 imx51_ipuv3_dc_map_conf(sc, 3, 1, 10, 0xfc); 345 imx51_ipuv3_dc_map_conf(sc, 3, 2, 15, 0xf8); 346 imx51_ipuv3_dc_map_clear(sc, 4); 347 imx51_ipuv3_dc_map_conf(sc, 4, 0, 5, 0xfc); 348 imx51_ipuv3_dc_map_conf(sc, 4, 1, 13, 0xfc); 349 imx51_ipuv3_dc_map_conf(sc, 4, 2, 21, 0xfc); 350 351 /* microcode */ 352 imx51_ipuv3_dc_template_command(sc, 353 5, 5, 8, 1, 5, 0, 0x180, 1); 354 imx51_ipuv3_dc_template_command(sc, 355 6, 5, 4, 1, 5, 0, 0x180, 1); 356 imx51_ipuv3_dc_template_command(sc, 357 7, 5, 0, 1, 5, 0, 0x180, 1); 358 359 reg = (4 << 5) | 0x2; 360 IPUV3_WRITE(sc, dc, IPU_DC_WR_CH_CONF_5, reg); 361 IPUV3_WRITE(sc, dc, IPU_DC_WR_CH_CONF_1, 0x4); 362 IPUV3_WRITE(sc, dc, IPU_DC_WR_CH_ADDR_5, 0x0); 363 IPUV3_WRITE(sc, dc, IPU_DC_GEN, 0x44); 364 365 imx51_ipuv3_set_routine_link(sc, DC_RL_CH_5, DC_RL_EVT_NL, 5, 3); 366 imx51_ipuv3_set_routine_link(sc, DC_RL_CH_5, DC_RL_EVT_EOL, 6, 2); 367 imx51_ipuv3_set_routine_link(sc, DC_RL_CH_5, DC_RL_EVT_NEW_DATA, 7, 1); 368 imx51_ipuv3_set_routine_link(sc, DC_RL_CH_5, DC_RL_EVT_NF, 0, 0); 369 imx51_ipuv3_set_routine_link(sc, DC_RL_CH_5, DC_RL_EVT_NFIELD, 0, 0); 370 imx51_ipuv3_set_routine_link(sc, DC_RL_CH_5, DC_RL_EVT_EOF, 0, 0); 371 imx51_ipuv3_set_routine_link(sc, DC_RL_CH_5, DC_RL_EVT_EOFIELD, 0, 0); 372 imx51_ipuv3_set_routine_link(sc, DC_RL_CH_5, DC_RL_EVT_NEW_CHAN, 0, 0); 373 imx51_ipuv3_set_routine_link(sc, DC_RL_CH_5, DC_RL_EVT_NEW_ADDR, 0, 0); 374 375 #ifdef IPUV3_DEBUG 376 int i; 377 printf("*** DC ***\n"); 378 for (i = 0; i <= 0x1C8; i += 4) 379 printf("0x%08X = 0x%08X\n", i, IPUV3_READ(sc, dc, i)); 380 printf("*** DCTEMPL ***\n"); 381 for (i = 0; i <= 0x100; i += 4) 382 printf("0x%08X = 0x%08X\n", i, IPUV3_READ(sc, dctmpl, i)); 383 #endif 384 } 385 386 static void 387 imx51_ipuv3_dc_display_config(struct imx51_ipuv3_softc *sc, int width) 388 { 389 DPRINTFN(5, ("%s : %d\n", __func__, __LINE__)); 390 391 IPUV3_WRITE(sc, dc, IPU_DC_DISP_CONF2_0, width); 392 } 393 394 static void 395 imx51_ipuv3_di_sync_conf(struct imx51_ipuv3_softc *sc, int no, 396 uint32_t reg_gen0, uint32_t reg_gen1, uint32_t repeat) 397 { 398 DPRINTFN(5, ("%s : %d\n", __func__, __LINE__)); 399 400 uint32_t reg; 401 402 IPUV3_WRITE(sc, di0, IPU_DI_SW_GEN0(no), reg_gen0); 403 IPUV3_WRITE(sc, di0, IPU_DI_SW_GEN1(no), reg_gen1); 404 reg = IPUV3_READ(sc, di0, IPU_DI_STP_REP(no)); 405 reg &= ~DI_STP_REP_MASK(no); 406 reg |= repeat << DI_STP_REP_SHIFT(no); 407 IPUV3_WRITE(sc, di0, IPU_DI_STP_REP(no), reg); 408 409 #ifdef IPUV3_DEBUG 410 printf("%s: no %d\n", __func__, no); 411 printf("%s: addr 0x%08X reg_gen0 0x%08X\n", __func__, 412 IPU_DI_SW_GEN0(no), reg_gen0); 413 printf("%s: addr 0x%08X reg_gen1 0x%08X\n", __func__, 414 IPU_DI_SW_GEN1(no), reg_gen1); 415 printf("%s: addr 0x%08X DI_STP_REP 0x%08X\n", __func__, 416 IPU_DI_STP_REP(no), reg); 417 #endif 418 } 419 420 static void 421 imx51_ipuv3_di_init(struct imx51_ipuv3_softc *sc) 422 { 423 DPRINTFN(5, ("%s : %d\n", __func__, __LINE__)); 424 425 uint32_t reg; 426 uint32_t div; 427 u_int ipuclk; 428 const struct lcd_panel_geometry *geom = sc->geometry; 429 430 #if NIMXCCM > 0 431 ipuclk = imx51_get_clock(IMX51CLK_IPU_HSP_CLK_ROOT); 432 #elif !defined(IMX51_IPU_HSP_CLOCK) 433 #error IMX51_CPU_HSP_CLOCK need to be defined. 434 #else 435 ipuclk = IMX51_IPU_HSP_CLOCK; 436 #endif 437 DPRINTFN(3, ("IPU HSP clock = %d\n", ipuclk)); 438 div = (ipuclk * 16) / geom->pixel_clk; 439 div = div < 16 ? 16 : div & 0xff8; 440 441 /* DI counter */ 442 reg = IPUV3_READ(sc, cm, IPU_CM_DISP_GEN); 443 reg &= ~(CM_DISP_GEN_DI1_COUNTER_RELEASE | 444 CM_DISP_GEN_DI0_COUNTER_RELEASE); 445 IPUV3_WRITE(sc, cm, IPU_CM_DISP_GEN, reg); 446 447 IPUV3_WRITE(sc, di0, IPU_DI_BS_CLKGEN0, div); 448 IPUV3_WRITE(sc, di0, IPU_DI_BS_CLKGEN1, 449 (div / 16) << DI_BS_CLKGEN1_DOWN_SHIFT); 450 #ifdef IPUV3_DEBUG 451 printf("%s: IPU_DI_BS_CLKGEN0 = 0x%08X\n", __func__, 452 IPUV3_READ(sc, di0, IPU_DI_BS_CLKGEN0)); 453 printf("%s: IPU_DI_BS_CLKGEN1 = 0x%08X\n", __func__, 454 IPUV3_READ(sc, di0, IPU_DI_BS_CLKGEN1)); 455 #endif 456 /* Display Time settings */ 457 reg = ((div / 16 - 1) << DI_DW_GEN_ACCESS_SIZE_SHIFT) | 458 ((div / 16 - 1) << DI_DW_GEN_COMPONNENT_SIZE_SHIFT) | 459 (3 << DI_DW_GEN_PIN_SHIFT(15)); 460 IPUV3_WRITE(sc, di0, IPU_DI_DW_GEN(0), reg); 461 #ifdef IPUV3_DEBUG 462 printf("%s: div = %d\n", __func__, div); 463 printf("%s: IPU_DI_DW_GEN(0) 0x%08X = 0x%08X\n", __func__, 464 IPU_DI_DW_GEN(0), reg); 465 #endif 466 467 /* Up & Down Data Wave Set */ 468 reg = (div / 16 * 2) << DI_DW_SET_DOWN_SHIFT; 469 IPUV3_WRITE(sc, di0, IPU_DI_DW_SET(0, 3), reg); 470 #ifdef IPUV3_DEBUG 471 printf("%s: IPU_DI_DW_SET(0, 3) 0x%08X = 0x%08X\n", __func__, 472 IPU_DI_DW_SET(0, 3), reg); 473 #endif 474 475 /* internal HSCYNC */ 476 imx51_ipuv3_di_sync_conf(sc, 1, 477 __DI_SW_GEN0(geom->panel_width + geom->hsync_width + 478 geom->left + geom->right - 1, 1, 0, 0), 479 __DI_SW_GEN1(0, 1, 0, 0, 0, 0, 0), 480 0); 481 482 /* HSYNC */ 483 imx51_ipuv3_di_sync_conf(sc, 2, 484 __DI_SW_GEN0(geom->panel_width + geom->hsync_width + 485 geom->left + geom->right - 1, 1, 0, 1), 486 __DI_SW_GEN1(1, 1, 0, geom->hsync_width * 2, 1, 0, 0), 487 0); 488 489 /* VSYNC */ 490 imx51_ipuv3_di_sync_conf(sc, 3, 491 __DI_SW_GEN0(geom->panel_height + geom->vsync_width + 492 geom->upper + geom->lower - 1, 2, 0, 0), 493 __DI_SW_GEN1(1, 1, 0, geom->vsync_width * 2, 2, 0, 0), 494 0); 495 496 IPUV3_WRITE(sc, di0, IPU_DI_SCR_CONF, 497 geom->panel_height + geom->vsync_width + geom->upper + 498 geom->lower - 1); 499 500 /* Active Lines Start */ 501 imx51_ipuv3_di_sync_conf(sc, 4, 502 __DI_SW_GEN0(0, 3, geom->vsync_width + geom->upper, 3), 503 __DI_SW_GEN1(0, 0, 4, 0, 0, 0, 0), 504 geom->panel_height); 505 506 /* Active Clock Start */ 507 imx51_ipuv3_di_sync_conf(sc, 5, 508 __DI_SW_GEN0(0, 1, geom->hsync_width + geom->left, 1), 509 __DI_SW_GEN1(0, 0, 5, 0, 0, 0, 0), 510 geom->panel_width); 511 512 IPUV3_WRITE(sc, di0, IPU_DI_SW_GEN0(6), 0); 513 IPUV3_WRITE(sc, di0, IPU_DI_SW_GEN1(6), 0); 514 IPUV3_WRITE(sc, di0, IPU_DI_SW_GEN0(7), 0); 515 IPUV3_WRITE(sc, di0, IPU_DI_SW_GEN1(7), 0); 516 IPUV3_WRITE(sc, di0, IPU_DI_SW_GEN0(8), 0); 517 IPUV3_WRITE(sc, di0, IPU_DI_SW_GEN1(8), 0); 518 IPUV3_WRITE(sc, di0, IPU_DI_SW_GEN0(9), 0); 519 IPUV3_WRITE(sc, di0, IPU_DI_SW_GEN1(9), 0); 520 521 reg = IPUV3_READ(sc, di0, IPU_DI_STP_REP(6)); 522 reg &= ~DI_STP_REP_MASK(6); 523 IPUV3_WRITE(sc, di0, IPU_DI_STP_REP(6), reg); 524 IPUV3_WRITE(sc, di0, IPU_DI_STP_REP(7), 0); 525 IPUV3_WRITE(sc, di0, IPU_DI_STP_REP(9), 0); 526 527 IPUV3_WRITE(sc, di0, IPU_DI_GENERAL, 0); 528 reg = ((3 - 1) << DI_SYNC_AS_GEN_VSYNC_SEL_SHIFT) | 0x2; 529 IPUV3_WRITE(sc, di0, IPU_DI_SYNC_AS_GEN, reg); 530 IPUV3_WRITE(sc, di0, IPU_DI_POL, DI_POL_DRDY_POLARITY_15); 531 532 /* release DI counter */ 533 reg = IPUV3_READ(sc, cm, IPU_CM_DISP_GEN); 534 reg |= CM_DISP_GEN_DI0_COUNTER_RELEASE; 535 IPUV3_WRITE(sc, cm, IPU_CM_DISP_GEN, reg); 536 537 #ifdef IPUV3_DEBUG 538 int i; 539 printf("*** DI0 ***\n"); 540 for (i = 0; i <= 0x174; i += 4) 541 printf("0x%08X = 0x%08X\n", i, IPUV3_READ(sc, di0, i)); 542 543 printf("%s: IPU_CM_DISP_GEN : 0x%08X\n", __func__, 544 IPUV3_READ(sc, cm, IPU_CM_DISP_GEN)); 545 printf("%s: IPU_DI_SYNC_AS_GEN : 0x%08X\n", __func__, 546 IPUV3_READ(sc, di0, IPU_DI_SYNC_AS_GEN)); 547 printf("%s: IPU_DI_GENERAL : 0x%08X\n", __func__, 548 IPUV3_READ(sc, di0, IPU_DI_GENERAL)); 549 printf("%s: IPU_DI_POL : 0x%08X\n", __func__, 550 IPUV3_READ(sc, di0, IPU_DI_POL)); 551 #endif 552 } 553 554 555 void 556 imx51_ipuv3_geometry(struct imx51_ipuv3_softc *sc, 557 const struct lcd_panel_geometry *geom) 558 { 559 DPRINTFN(5, ("%s : %d\n", __func__, __LINE__)); 560 561 sc->geometry = geom; 562 563 #ifdef IPUV3_DEBUG 564 printf("%s: screen height = %d\n",__func__ , geom->panel_height); 565 printf("%s: width = %d\n",__func__ , geom->panel_width); 566 printf("%s: IPU Clock = %d\n", __func__, 567 imx51_get_clock(IMX51CLK_IPU_HSP_CLK_ROOT)); 568 printf("%s: Pixel Clock = %d\n", __func__, geom->pixel_clk); 569 #endif 570 571 imx51_ipuv3_di_init(sc); 572 573 #ifdef IPUV3_DEBUG 574 printf("%s: IPU_CM_DISP_GEN : 0x%08X\n", __func__, 575 IPUV3_READ(sc, cm, IPU_CM_DISP_GEN)); 576 #endif 577 578 imx51_ipuv3_dc_display_config(sc, geom->panel_width); 579 580 return; 581 } 582 583 /* 584 * Initialize the IPUV3 controller. 585 */ 586 static void 587 imx51_ipuv3_initialize(struct imx51_ipuv3_softc *sc, 588 const struct lcd_panel_geometry *geom) 589 { 590 uint32_t reg; 591 592 DPRINTFN(5, ("%s : %d\n", __func__, __LINE__)); 593 594 IPUV3_WRITE(sc, cm, IPU_CM_CONF, 0); 595 596 /* reset */ 597 IPUV3_WRITE(sc, cm, IPU_CM_MEM_RST, CM_MEM_START | CM_MEM_EN); 598 while (IPUV3_READ(sc, cm, IPU_CM_MEM_RST) & CM_MEM_START) 599 ; /* wait */ 600 601 imx51_ipuv3_dmfc_init(sc); 602 imx51_ipuv3_dc_init(sc); 603 604 imx51_ipuv3_geometry(sc, geom); 605 606 /* set global alpha */ 607 IPUV3_WRITE(sc, dp, IPU_DP_GRAPH_WIND_CTRL_SYNC, 0x80 << 24); 608 IPUV3_WRITE(sc, dp, IPU_DP_COM_CONF_SYNC, DP_DP_GWAM_SYNC); 609 610 reg = IPUV3_READ(sc, cm, IPU_CM_DISP_GEN); 611 reg |= CM_DISP_GEN_MCU_MAX_BURST_STOP | 612 CM_DISP_GEN_MCU_T(0x8); 613 IPUV3_WRITE(sc, cm, IPU_CM_DISP_GEN, reg); 614 } 615 616 static void 617 imx51_ipuv3_init_screen(void *cookie, struct vcons_screen *scr, 618 int existing, long *defattr) 619 { 620 DPRINTFN(5, ("%s : %d\n", __func__, __LINE__)); 621 622 struct imx51_ipuv3_softc *sc = cookie; 623 struct rasops_info *ri = &scr->scr_ri; 624 struct imx51_wsscreen_descr *descr = &imx51_ipuv3_stdscreen; 625 626 if ((scr == &sc->console) && (sc->vd.active != NULL)) 627 return; 628 629 ri->ri_bits = sc->active->buf_va; 630 631 scr->scr_flags |= VCONS_DONT_READ; 632 if (existing) 633 ri->ri_flg |= RI_CLEAR; 634 635 imx51_ipuv3_setup_rasops(sc, ri, descr, sc->geometry); 636 637 ri->ri_caps = WSSCREEN_WSCOLORS; 638 639 rasops_reconfig(ri, 640 ri->ri_height / ri->ri_font->fontheight, 641 ri->ri_width / ri->ri_font->fontwidth); 642 643 ri->ri_hw = scr; 644 } 645 646 /* 647 * Common driver attachment code. 648 */ 649 void 650 imx51_ipuv3_attach_sub(struct imx51_ipuv3_softc *sc, 651 struct axi_attach_args *axia, const struct lcd_panel_geometry *geom) 652 { 653 DPRINTFN(5, ("%s : %d\n", __func__, __LINE__)); 654 655 bus_space_tag_t iot = axia->aa_iot; 656 bus_space_handle_t ioh; 657 int error; 658 659 aprint_normal(": i.MX51 IPUV3 controller\n"); 660 661 sc->n_screens = 0; 662 LIST_INIT(&sc->screens); 663 664 sc->iot = iot; 665 sc->dma_tag = &imx_bus_dma_tag; 666 667 /* map controller registers */ 668 error = bus_space_map(iot, IPU_CM_BASE, IPU_CM_SIZE, 0, &ioh); 669 if (error) 670 goto fail_retarn_cm; 671 sc->cm_ioh = ioh; 672 673 /* map Display Multi FIFO Controller registers */ 674 error = bus_space_map(iot, IPU_DMFC_BASE, IPU_DMFC_SIZE, 0, &ioh); 675 if (error) 676 goto fail_retarn_dmfc; 677 sc->dmfc_ioh = ioh; 678 679 /* map Display Interface registers */ 680 error = bus_space_map(iot, IPU_DI0_BASE, IPU_DI0_SIZE, 0, &ioh); 681 if (error) 682 goto fail_retarn_di0; 683 sc->di0_ioh = ioh; 684 685 /* map Display Processor registers */ 686 error = bus_space_map(iot, IPU_DP_BASE, IPU_DP_SIZE, 0, &ioh); 687 if (error) 688 goto fail_retarn_dp; 689 sc->dp_ioh = ioh; 690 691 /* map Display Controller registers */ 692 error = bus_space_map(iot, IPU_DC_BASE, IPU_DC_SIZE, 0, &ioh); 693 if (error) 694 goto fail_retarn_dc; 695 sc->dc_ioh = ioh; 696 697 /* map Image DMA Controller registers */ 698 error = bus_space_map(iot, IPU_IDMAC_BASE, IPU_IDMAC_SIZE, 0, &ioh); 699 if (error) 700 goto fail_retarn_idmac; 701 sc->idmac_ioh = ioh; 702 703 /* map CPMEM registers */ 704 error = bus_space_map(iot, IPU_CPMEM_BASE, IPU_CPMEM_SIZE, 0, &ioh); 705 if (error) 706 goto fail_retarn_cpmem; 707 sc->cpmem_ioh = ioh; 708 709 /* map DCTEMPL registers */ 710 error = bus_space_map(iot, IPU_DCTMPL_BASE, IPU_DCTMPL_SIZE, 0, &ioh); 711 if (error) 712 goto fail_retarn_dctmpl; 713 sc->dctmpl_ioh = ioh; 714 715 #ifdef notyet 716 sc->ih = imx51_ipuv3_intr_establish(IMX51_INT_IPUV3, IPL_BIO, 717 ipuv3intr, sc); 718 if (sc->ih == NULL) { 719 aprint_error_dev(sc->dev, 720 "unable to establish interrupt at irq %d\n", 721 IMX51_INT_IPUV3); 722 return; 723 } 724 #endif 725 726 imx51_ipuv3_initialize(sc, geom); 727 728 #if NWSDISPLAY > 0 729 struct imx51_wsscreen_descr *descr = &imx51_ipuv3_stdscreen; 730 struct imx51_ipuv3_screen *scr; 731 732 sc->mode = WSDISPLAYIO_MODE_EMUL; 733 error = imx51_ipuv3_new_screen(sc, descr->depth, &scr); 734 if (error) { 735 aprint_error_dev(sc->dev, 736 "unable to create new screen (errno=%d)", error); 737 return; 738 } 739 sc->active = scr; 740 741 vcons_init(&sc->vd, sc, &imx51_ipuv3_stdscreen.c, 742 &imx51_ipuv3_accessops); 743 sc->vd.init_screen = imx51_ipuv3_init_screen; 744 745 #ifdef IPUV3_DEBUG 746 printf("%s: IPUV3 console ? %d\n", __func__, imx51_ipuv3_console.is_console); 747 #endif 748 749 struct rasops_info *ri; 750 long defattr; 751 ri = &sc->console.scr_ri; 752 753 if (imx51_ipuv3_console.is_console) { 754 vcons_init_screen(&sc->vd, &sc->console, 1, 755 &defattr); 756 sc->console.scr_flags |= VCONS_SCREEN_IS_STATIC; 757 758 imx51_ipuv3_stdscreen.c.nrows = ri->ri_rows; 759 imx51_ipuv3_stdscreen.c.ncols = ri->ri_cols; 760 imx51_ipuv3_stdscreen.c.textops = &ri->ri_ops; 761 imx51_ipuv3_stdscreen.c.capabilities = ri->ri_caps; 762 763 wsdisplay_cnattach(&descr->c, ri, 0, 0, defattr); 764 vcons_replay_msgbuf(&sc->console); 765 766 imx51_ipuv3_start_dma(sc, scr); 767 768 aprint_normal_dev(sc->dev, "console\n"); 769 } else { 770 /* 771 * since we're not the console we can postpone the rest 772 * until someone actually allocates a screen for us 773 */ 774 (*ri->ri_ops.allocattr)(ri, 0, 0, 0, &defattr); 775 } 776 777 struct wsemuldisplaydev_attach_args aa; 778 aa.console = imx51_ipuv3_console.is_console; 779 aa.scrdata = &imx51_ipuv3_screen_list; 780 aa.accessops = &imx51_ipuv3_accessops; 781 aa.accesscookie = &sc->vd; 782 783 config_found(sc->dev, &aa, wsemuldisplaydevprint); 784 #endif 785 786 return; 787 788 fail_retarn_dctmpl: 789 bus_space_unmap(sc->iot, sc->cpmem_ioh, IPU_CPMEM_SIZE); 790 fail_retarn_cpmem: 791 bus_space_unmap(sc->iot, sc->idmac_ioh, IPU_IDMAC_SIZE); 792 fail_retarn_idmac: 793 bus_space_unmap(sc->iot, sc->dc_ioh, IPU_DC_SIZE); 794 fail_retarn_dp: 795 bus_space_unmap(sc->iot, sc->dp_ioh, IPU_DP_SIZE); 796 fail_retarn_dc: 797 bus_space_unmap(sc->iot, sc->di0_ioh, IPU_DI0_SIZE); 798 fail_retarn_di0: 799 bus_space_unmap(sc->iot, sc->dmfc_ioh, IPU_DMFC_SIZE); 800 fail_retarn_dmfc: 801 bus_space_unmap(sc->iot, sc->dc_ioh, IPU_CM_SIZE); 802 fail_retarn_cm: 803 aprint_error_dev(sc->dev, 804 "failed to map registers (errno=%d)\n", error); 805 return; 806 } 807 808 int 809 imx51_ipuv3_cnattach(const struct lcd_panel_geometry *geom) 810 { 811 DPRINTFN(5, ("%s : %d\n", __func__, __LINE__)); 812 imx51_ipuv3_console.is_console = 1; 813 return 0; 814 } 815 816 #ifdef notyet 817 /* 818 * Interrupt handler. 819 */ 820 int 821 ipuv3intr(void *arg) 822 { 823 DPRINTFN(5, ("%s : %d\n", __func__, __LINE__)); 824 825 struct imx51_ipuv3_softc *sc = (struct imx51_ipuv3_softc *)arg; 826 bus_space_tag_t iot = sc->iot; 827 bus_space_handle_t ioh = sc->dc_ioh; 828 uint32_t status; 829 830 status = IPUV3_READ(ioh, V3CR); 831 /* Clear stickey status bits */ 832 IPUV3_WRITE(ioh, V3CR, status); 833 834 return 1; 835 } 836 #endif 837 838 static void 839 imx51_ipuv3_write_dmaparam(struct imx51_ipuv3_softc *sc, 840 int ch, uint32_t *value, int size) 841 { 842 DPRINTFN(5, ("%s : %d\n", __func__, __LINE__)); 843 844 int i; 845 uint32_t addr = ch * 0x40; 846 847 for (i = 0; i < size; i++) { 848 IPUV3_WRITE(sc, cpmem, addr + ((i % 5) * 0x4) + 849 ((i / 5) * 0x20), value[i]); 850 #ifdef IPUV3_DEBUG 851 printf("%s: addr = 0x%08X, val = 0x%08X\n", __func__, 852 addr + ((i % 5) * 0x4) + ((i / 5) * 0x20), 853 IPUV3_READ(sc, cpmem, addr + ((i % 5) * 0x4) + 854 ((i / 5) * 0x20))); 855 #endif 856 } 857 } 858 859 static void 860 imx51_ipuv3_build_param(struct imx51_ipuv3_softc *sc, 861 struct imx51_ipuv3_screen *scr, 862 uint32_t *params) 863 { 864 const struct lcd_panel_geometry *geom = sc->geometry; 865 866 DPRINTFN(5, ("%s : %d\n", __func__, __LINE__)); 867 868 imx51_ipuv3_set_idma_param(params, IDMAC_Ch_PARAM_FW, 869 (geom->panel_width - 1)); 870 imx51_ipuv3_set_idma_param(params, IDMAC_Ch_PARAM_FH, 871 (geom->panel_height - 1)); 872 imx51_ipuv3_set_idma_param(params, IDMAC_Ch_PARAM_EBA0, 873 scr->segs[0].ds_addr >> 3); 874 imx51_ipuv3_set_idma_param(params, IDMAC_Ch_PARAM_EBA1, 875 scr->segs[0].ds_addr >> 3); 876 imx51_ipuv3_set_idma_param(params, IDMAC_Ch_PARAM_SL, 877 (scr->stride - 1)); 878 879 imx51_ipuv3_set_idma_param(params, IDMAC_Ch_PARAM_PFS, 0x7); 880 imx51_ipuv3_set_idma_param(params, IDMAC_Ch_PARAM_NPB, 32 - 1); 881 882 switch (scr->depth) { 883 case 32: 884 /* ARBG888 */ 885 imx51_ipuv3_set_idma_param(params, IDMAC_Ch_PARAM_BPP, 0x0); 886 887 imx51_ipuv3_set_idma_param(params, IDMAC_Ch_PARAM_OFS0, 0); 888 imx51_ipuv3_set_idma_param(params, IDMAC_Ch_PARAM_OFS1, 8); 889 imx51_ipuv3_set_idma_param(params, IDMAC_Ch_PARAM_OFS2, 16); 890 imx51_ipuv3_set_idma_param(params, IDMAC_Ch_PARAM_OFS3, 24); 891 892 imx51_ipuv3_set_idma_param(params, IDMAC_Ch_PARAM_WID0, 8 - 1); 893 imx51_ipuv3_set_idma_param(params, IDMAC_Ch_PARAM_WID1, 8 - 1); 894 imx51_ipuv3_set_idma_param(params, IDMAC_Ch_PARAM_WID2, 8 - 1); 895 imx51_ipuv3_set_idma_param(params, IDMAC_Ch_PARAM_WID3, 8 - 1); 896 break; 897 case 24: 898 /* RBG888 */ 899 imx51_ipuv3_set_idma_param(params, IDMAC_Ch_PARAM_BPP, 0x1); 900 901 imx51_ipuv3_set_idma_param(params, IDMAC_Ch_PARAM_OFS0, 0); 902 imx51_ipuv3_set_idma_param(params, IDMAC_Ch_PARAM_OFS1, 8); 903 imx51_ipuv3_set_idma_param(params, IDMAC_Ch_PARAM_OFS2, 16); 904 imx51_ipuv3_set_idma_param(params, IDMAC_Ch_PARAM_OFS3, 24); 905 906 imx51_ipuv3_set_idma_param(params, IDMAC_Ch_PARAM_WID0, 8 - 1); 907 imx51_ipuv3_set_idma_param(params, IDMAC_Ch_PARAM_WID1, 8 - 1); 908 imx51_ipuv3_set_idma_param(params, IDMAC_Ch_PARAM_WID2, 8 - 1); 909 imx51_ipuv3_set_idma_param(params, IDMAC_Ch_PARAM_WID3, 0); 910 break; 911 case 16: 912 /* RBG565 */ 913 imx51_ipuv3_set_idma_param(params, IDMAC_Ch_PARAM_BPP, 0x3); 914 915 imx51_ipuv3_set_idma_param(params, IDMAC_Ch_PARAM_OFS0, 0); 916 imx51_ipuv3_set_idma_param(params, IDMAC_Ch_PARAM_OFS1, 5); 917 imx51_ipuv3_set_idma_param(params, IDMAC_Ch_PARAM_OFS2, 11); 918 imx51_ipuv3_set_idma_param(params, IDMAC_Ch_PARAM_OFS3, 16); 919 920 imx51_ipuv3_set_idma_param(params, IDMAC_Ch_PARAM_WID0, 5 - 1); 921 imx51_ipuv3_set_idma_param(params, IDMAC_Ch_PARAM_WID1, 6 - 1); 922 imx51_ipuv3_set_idma_param(params, IDMAC_Ch_PARAM_WID2, 5 - 1); 923 imx51_ipuv3_set_idma_param(params, IDMAC_Ch_PARAM_WID3, 0); 924 break; 925 default: 926 panic("%s: unsupported depth %d\n", __func__, scr->depth); 927 break; 928 } 929 930 imx51_ipuv3_set_idma_param(params, IDMAC_Ch_PARAM_ID, 1); 931 } 932 933 static void 934 imx51_ipuv3_set_idma_param(uint32_t *params, uint32_t name, uint32_t val) 935 { 936 int word = (name >> 16) & 0xff; 937 int shift = (name >> 8) & 0xff; 938 int width = name & 0xff; 939 int index; 940 941 DPRINTFN(5, ("%s : %d\n", __func__, __LINE__)); 942 943 index = word * 5; 944 index += shift / 32; 945 shift = shift % 32; 946 947 params[index] |= val << shift; 948 shift = 32 - shift; 949 950 if (width > shift) 951 params[index+1] |= val >> shift; 952 } 953 954 /* 955 * Enable DMA to cause the display to be refreshed periodically. 956 * This brings the screen to life... 957 */ 958 void 959 imx51_ipuv3_start_dma(struct imx51_ipuv3_softc *sc, 960 struct imx51_ipuv3_screen *scr) 961 { 962 int save; 963 uint32_t params[10]; 964 uint32_t reg; 965 966 DPRINTFN(3, ("%s: Pixel depth = %d\n", __func__, scr->depth)); 967 968 reg = IPUV3_READ(sc, idmac, IPU_IDMAC_CH_EN_1); 969 reg &= ~__BIT(CH_PANNEL_BG); 970 IPUV3_WRITE(sc, idmac, IPU_IDMAC_CH_EN_1, reg); 971 972 memset(params, 0, sizeof(params)); 973 imx51_ipuv3_build_param(sc, scr, params); 974 975 save = disable_interrupts(I32_bit); 976 977 /* IDMAC configuration */ 978 imx51_ipuv3_write_dmaparam(sc, CH_PANNEL_BG, params, 979 sizeof(params) / sizeof(params[0])); 980 981 IPUV3_WRITE(sc, idmac, IPU_IDMAC_CH_PRI_1, __BIT(CH_PANNEL_BG)); 982 983 /* double buffer */ 984 reg = IPUV3_READ(sc, cm, IPU_CM_CH_DB_MODE_SEL_0); 985 reg |= __BIT(CH_PANNEL_BG); 986 IPUV3_WRITE(sc, cm, IPU_CM_CH_DB_MODE_SEL_0, reg); 987 988 reg = IPUV3_READ(sc, idmac, IPU_IDMAC_CH_EN_1); 989 reg |= __BIT(CH_PANNEL_BG); 990 IPUV3_WRITE(sc, idmac, IPU_IDMAC_CH_EN_1, reg); 991 992 reg = IPUV3_READ(sc, cm, IPU_CM_GPR); 993 reg &= ~CM_GPR_IPU_CH_BUF0_RDY0_CLR; 994 IPUV3_WRITE(sc, cm, IPU_CM_GPR, reg); 995 996 IPUV3_WRITE(sc, cm, IPU_CM_CUR_BUF_0, __BIT(CH_PANNEL_BG)); 997 998 restore_interrupts(save); 999 1000 imx51_ipuv3_enable_display(sc); 1001 1002 #ifdef IPUV3_DEBUG 1003 imx51_ipuv3_dump(sc); 1004 #endif 1005 } 1006 1007 /* 1008 * Disable screen refresh. 1009 */ 1010 static void 1011 imx51_ipuv3_stop_dma(struct imx51_ipuv3_softc *sc) 1012 { 1013 DPRINTFN(5, ("%s : %d\n", __func__, __LINE__)); 1014 1015 return; 1016 } 1017 1018 /* 1019 * Create and initialize a new screen buffer. 1020 */ 1021 int 1022 imx51_ipuv3_new_screen(struct imx51_ipuv3_softc *sc, int depth, 1023 struct imx51_ipuv3_screen **scrpp) 1024 { 1025 const struct lcd_panel_geometry *geometry; 1026 struct imx51_ipuv3_screen *scr = NULL; 1027 int width, height; 1028 bus_size_t size; 1029 int error; 1030 int busdma_flag = (cold ? BUS_DMA_NOWAIT : BUS_DMA_WAITOK); 1031 1032 DPRINTFN(5, ("%s : %d\n", __func__, __LINE__)); 1033 1034 geometry = sc->geometry; 1035 1036 width = geometry->panel_width; 1037 height = geometry->panel_height; 1038 1039 scr = malloc(sizeof(*scr), M_DEVBUF, M_NOWAIT); 1040 if (scr == NULL) 1041 return ENOMEM; 1042 1043 memset(scr, 0, sizeof(*scr)); 1044 1045 scr->nsegs = 0; 1046 scr->depth = depth; 1047 scr->stride = width * depth / 8; 1048 scr->buf_size = size = scr->stride * height; 1049 scr->buf_va = NULL; 1050 1051 error = bus_dmamem_alloc(sc->dma_tag, size, 16, 0, scr->segs, 1, 1052 &scr->nsegs, busdma_flag); 1053 1054 if (error || scr->nsegs != 1) { 1055 /* XXX: 1056 * Actually we can handle nsegs>1 case by means 1057 * of multiple DMA descriptors for a panel. It 1058 * will make code here a bit hairly. 1059 */ 1060 if (error == 0) 1061 error = E2BIG; 1062 goto bad; 1063 } 1064 1065 error = bus_dmamem_map(sc->dma_tag, scr->segs, scr->nsegs, size, 1066 (void **)&scr->buf_va, busdma_flag | BUS_DMA_COHERENT); 1067 if (error) 1068 goto bad; 1069 1070 memset(scr->buf_va, 0, scr->buf_size); 1071 1072 /* map memory for DMA */ 1073 error = bus_dmamap_create(sc->dma_tag, 1024*1024*2, 1, 1024*1024*2, 0, 1074 busdma_flag, &scr->dma); 1075 if (error) 1076 goto bad; 1077 1078 error = bus_dmamap_load(sc->dma_tag, scr->dma, scr->buf_va, size, 1079 NULL, busdma_flag); 1080 if (error) 1081 goto bad; 1082 1083 LIST_INSERT_HEAD(&sc->screens, scr, link); 1084 sc->n_screens++; 1085 1086 #ifdef IPUV3_DEBUG 1087 printf("%s: screen buffer width %d\n", __func__, width); 1088 printf("%s: screen buffer height %d\n", __func__, height); 1089 printf("%s: screen buffer depth %d\n", __func__, depth); 1090 printf("%s: screen buffer stride %d\n", __func__, scr->stride); 1091 printf("%s: screen buffer size 0x%08X\n", __func__, 1092 (uint32_t)scr->buf_size); 1093 printf("%s: screen buffer addr virtual %p\n", __func__, scr->buf_va); 1094 printf("%s: screen buffer addr physical %p\n", __func__, 1095 (void *)scr->segs[0].ds_addr); 1096 #endif 1097 1098 scr->map_size = size; /* used when unmap this. */ 1099 1100 *scrpp = scr; 1101 1102 return 0; 1103 1104 bad: 1105 #ifdef IPUV3_DEBUG 1106 printf("%s: error = 0x%08X\n", __func__, error); 1107 #endif 1108 if (scr) { 1109 if (scr->buf_va) 1110 bus_dmamem_unmap(sc->dma_tag, scr->buf_va, size); 1111 if (scr->nsegs) 1112 bus_dmamem_free(sc->dma_tag, scr->segs, scr->nsegs); 1113 free(scr, M_DEVBUF); 1114 } 1115 *scrpp = NULL; 1116 return error; 1117 } 1118 1119 #if NWSDISPLAY > 0 1120 /* 1121 * Initialize rasops for a screen, as well as struct wsscreen_descr if this 1122 * is the first screen creation. 1123 */ 1124 static void 1125 imx51_ipuv3_setup_rasops(struct imx51_ipuv3_softc *sc, struct rasops_info *rinfo, 1126 struct imx51_wsscreen_descr *descr, 1127 const struct lcd_panel_geometry *geom) 1128 { 1129 1130 DPRINTFN(5, ("%s : %d\n", __func__, __LINE__)); 1131 1132 rinfo->ri_flg = descr->flags; 1133 rinfo->ri_depth = descr->depth; 1134 rinfo->ri_width = geom->panel_width; 1135 rinfo->ri_height = geom->panel_height; 1136 rinfo->ri_stride = rinfo->ri_width * rinfo->ri_depth / 8; 1137 1138 /* swap B and R */ 1139 if (descr->depth == 16) { 1140 rinfo->ri_rnum = 5; 1141 rinfo->ri_rpos = 11; 1142 rinfo->ri_gnum = 6; 1143 rinfo->ri_gpos = 5; 1144 rinfo->ri_bnum = 5; 1145 rinfo->ri_bpos = 0; 1146 } 1147 1148 if (descr->c.nrows == 0) { 1149 /* get rasops to compute screen size the first time */ 1150 rasops_init(rinfo, 100, 100); 1151 } else { 1152 rasops_init(rinfo, descr->c.nrows, descr->c.ncols); 1153 } 1154 1155 descr->c.nrows = rinfo->ri_rows; 1156 descr->c.ncols = rinfo->ri_cols; 1157 descr->c.capabilities = rinfo->ri_caps; 1158 descr->c.textops = &rinfo->ri_ops; 1159 } 1160 #endif 1161 /* 1162 * Power management 1163 */ 1164 void 1165 imx51_ipuv3_suspend(struct imx51_ipuv3_softc *sc) 1166 { 1167 DPRINTFN(5, ("%s : %d\n", __func__, __LINE__)); 1168 1169 if (sc->active) { 1170 imx51_ipuv3_stop_dma(sc); 1171 } 1172 } 1173 1174 void 1175 imx51_ipuv3_resume(struct imx51_ipuv3_softc *sc) 1176 { 1177 DPRINTFN(5, ("%s : %d\n", __func__, __LINE__)); 1178 1179 if (sc->active) { 1180 imx51_ipuv3_initialize(sc, sc->geometry); 1181 imx51_ipuv3_start_dma(sc, sc->active); 1182 } 1183 } 1184 1185 void 1186 imx51_ipuv3_power(int why, void *v) 1187 { 1188 DPRINTFN(5, ("%s : %d\n", __func__, __LINE__)); 1189 1190 struct imx51_ipuv3_softc *sc = v; 1191 1192 switch (why) { 1193 case PWR_SUSPEND: 1194 case PWR_STANDBY: 1195 imx51_ipuv3_suspend(sc); 1196 break; 1197 1198 case PWR_RESUME: 1199 imx51_ipuv3_resume(sc); 1200 break; 1201 } 1202 } 1203 1204 #if NWSDISPLAY > 0 1205 int 1206 imx51_ipuv3_ioctl(void *v, void *vs, u_long cmd, void *data, int flag, 1207 struct lwp *l) 1208 { 1209 DPRINTFN(5, ("%s : %d\n", __func__, __LINE__)); 1210 1211 struct vcons_data *vd = v; 1212 struct imx51_ipuv3_softc *sc = vd->cookie; 1213 struct wsdisplay_fbinfo *wsdisp_info; 1214 struct vcons_screen *ms = vd->active; 1215 1216 switch (cmd) { 1217 case WSDISPLAYIO_GTYPE: 1218 *(int *)data = WSDISPLAY_TYPE_IMXIPU; 1219 return 0; 1220 1221 case WSDISPLAYIO_GINFO: 1222 wsdisp_info = (struct wsdisplay_fbinfo *)data; 1223 wsdisp_info->height = ms->scr_ri.ri_height; 1224 wsdisp_info->width = ms->scr_ri.ri_width; 1225 wsdisp_info->depth = ms->scr_ri.ri_depth; 1226 wsdisp_info->cmsize = 0; 1227 return 0; 1228 1229 case WSDISPLAYIO_LINEBYTES: 1230 *(u_int *)data = ms->scr_ri.ri_stride; 1231 return 0; 1232 1233 case WSDISPLAYIO_GETCMAP: 1234 case WSDISPLAYIO_PUTCMAP: 1235 return EPASSTHROUGH; /* XXX Colormap */ 1236 1237 case WSDISPLAYIO_SVIDEO: 1238 if (*(int *)data == WSDISPLAYIO_VIDEO_ON) { 1239 /* turn it on */ 1240 } 1241 else { 1242 /* start IPUV3 shutdown */ 1243 /* sleep until interrupt */ 1244 } 1245 return 0; 1246 1247 case WSDISPLAYIO_GVIDEO: 1248 *(u_int *)data = WSDISPLAYIO_VIDEO_ON; 1249 return 0; 1250 1251 case WSDISPLAYIO_GCURPOS: 1252 case WSDISPLAYIO_SCURPOS: 1253 case WSDISPLAYIO_GCURMAX: 1254 case WSDISPLAYIO_GCURSOR: 1255 case WSDISPLAYIO_SCURSOR: 1256 return EPASSTHROUGH; /* XXX */ 1257 case WSDISPLAYIO_SMODE: 1258 { 1259 int new_mode = *(int*)data; 1260 1261 /* notify the bus backend */ 1262 if (new_mode != sc->mode) { 1263 sc->mode = new_mode; 1264 if(new_mode == WSDISPLAYIO_MODE_EMUL) 1265 vcons_redraw_screen(ms); 1266 } 1267 } 1268 return 0; 1269 } 1270 1271 return EPASSTHROUGH; 1272 } 1273 1274 paddr_t 1275 imx51_ipuv3_mmap(void *v, void *vs, off_t offset, int prot) 1276 { 1277 DPRINTFN(5, ("%s : %d\n", __func__, __LINE__)); 1278 1279 struct vcons_data *vd = v; 1280 struct imx51_ipuv3_softc *sc = vd->cookie; 1281 struct imx51_ipuv3_screen *scr = sc->active; 1282 1283 return bus_dmamem_mmap(sc->dma_tag, scr->segs, scr->nsegs, 1284 offset, prot, 1285 BUS_DMA_WAITOK | BUS_DMA_COHERENT); 1286 } 1287 #endif /* NWSDISPLAY > 0 */ 1288 1289