1 /*- 2 * Copyright 2015 Oleksandr Tymoshenko <gonzo@freebsd.org> 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 27 #include <sys/param.h> 28 #include <sys/systm.h> 29 #include <sys/kernel.h> 30 #include <sys/module.h> 31 #include <sys/clock.h> 32 #include <sys/eventhandler.h> 33 #include <sys/time.h> 34 #include <sys/bus.h> 35 #include <sys/lock.h> 36 #include <sys/mutex.h> 37 #include <sys/resource.h> 38 #include <sys/rman.h> 39 #include <sys/sysctl.h> 40 #include <sys/fbio.h> 41 #include <sys/consio.h> 42 43 #include <machine/bus.h> 44 45 #include <dev/ofw/openfirm.h> 46 #include <dev/ofw/ofw_bus.h> 47 #include <dev/ofw/ofw_bus_subr.h> 48 49 #include <dev/fb/fbreg.h> 50 #include <dev/vt/vt.h> 51 52 #include <dev/videomode/videomode.h> 53 #include <dev/videomode/edidvar.h> 54 55 #include <arm/freescale/imx/imx6_src.h> 56 #include <arm/freescale/imx/imx_ccmvar.h> 57 58 #include "fb_if.h" 59 #include "crtc_if.h" 60 61 static int have_ipu = 0; 62 63 #define MODE_HBP(mode) ((mode)->htotal - (mode)->hsync_end) 64 #define MODE_HFP(mode) ((mode)->hsync_start - (mode)->hdisplay) 65 #define MODE_HSW(mode) ((mode)->hsync_end - (mode)->hsync_start) 66 #define MODE_VBP(mode) ((mode)->vtotal - (mode)->vsync_end) 67 #define MODE_VFP(mode) ((mode)->vsync_start - (mode)->vdisplay) 68 #define MODE_VSW(mode) ((mode)->vsync_end - (mode)->vsync_start) 69 70 #define MODE_BPP 16 71 #define MODE_PIXEL_CLOCK_INVERT 1 72 73 #define DMA_CHANNEL 23 74 #define DC_CHAN5 5 75 #define DI_PORT 0 76 77 #define IPU_LOCK(_sc) mtx_lock(&(_sc)->sc_mtx) 78 #define IPU_UNLOCK(_sc) mtx_unlock(&(_sc)->sc_mtx) 79 #define IPU_LOCK_INIT(_sc) mtx_init(&(_sc)->sc_mtx, \ 80 device_get_nameunit(_sc->sc_dev), "ipu", MTX_DEF) 81 #define IPU_LOCK_DESTROY(_sc) mtx_destroy(&(_sc)->sc_mtx) 82 83 #define IPU_READ4(_sc, reg) bus_read_4((_sc)->sc_mem_res, (reg)) 84 #define IPU_WRITE4(_sc, reg, value) \ 85 bus_write_4((_sc)->sc_mem_res, (reg), (value)) 86 87 #define CPMEM_BASE 0x300000 88 #define DC_TEMPL_BASE 0x380000 89 90 /* Microcode */ 91 /* Word 1 */ 92 #define TEMPLATE_SYNC(v) ((v) << 0) 93 #define TEMPLATE_GLUELOGIC(v) ((v) << 4) 94 #define TEMPLATE_MAPPING(v) ((v) << 15) 95 #define TEMPLATE_WAVEFORM(v) ((v) << 11) 96 #define GLUELOGIC_KEEP_ASSERTED (1 << 3) 97 #define GLUELOGIC_KEEP_NEGATED (1 << 2) 98 /* Word 2 */ 99 #define TEMPLATE_OPCODE(v) ((v) << 4) 100 #define OPCODE_WROD 0x18 101 #define TEMPLATE_STOP (1 << 9) 102 103 #define IPU_CONF 0x200000 104 #define IPU_CONF_DMFC_EN (1 << 10) 105 #define IPU_CONF_DC_EN (1 << 9) 106 #define IPU_CONF_DI1_EN (1 << 7) 107 #define IPU_CONF_DI0_EN (1 << 6) 108 #define IPU_CONF_DP_EN (1 << 5) 109 #define IPU_DISP_GEN 0x2000C4 110 #define DISP_GEN_DI1_CNTR_RELEASE (1 << 25) 111 #define DISP_GEN_DI0_CNTR_RELEASE (1 << 24) 112 #define DISP_GEN_MCU_MAX_BURST_STOP (1 << 22) 113 #define DISP_GEN_MCU_T_SHIFT 18 114 #define IPU_MEM_RST 0x2000DC 115 #define IPU_MEM_RST_START (1 << 31) 116 #define IPU_MEM_RST_ALL 0x807FFFFF 117 #define IPU_CH_DB_MODE_SEL_0 0x200150 118 #define IPU_CH_DB_MODE_SEL_1 0x200154 119 #define IPU_CUR_BUF_0 0x20023C 120 #define IPU_CUR_BUF_1 0x200240 121 122 #define IPU_IDMAC_CH_EN_1 0x208004 123 #define IPU_IDMAC_CH_EN_2 0x208008 124 #define IPU_IDMAC_CH_PRI_1 0x208014 125 #define IPU_IDMAC_CH_PRI_2 0x208018 126 127 #define IPU_DI0_GENERAL 0x240000 128 #define DI_CLOCK_EXTERNAL (1 << 20) 129 #define DI_GENERAL_POL_CLK (1 << 17) 130 #define DI_GENERAL_POLARITY_3 (1 << 2) 131 #define DI_GENERAL_POLARITY_2 (1 << 1) 132 #define IPU_DI0_BS_CLKGEN0 0x240004 133 #define DI_BS_CLKGEN0(_int, _frac) (((_int) << 4) | (_frac)) 134 #define IPU_DI0_BS_CLKGEN1 0x240008 135 #define DI_BS_CLKGEN1_DOWN(_int, _frac) ((((_int) << 1) | (_frac)) << 16) 136 #define IPU_DI0_SW_GEN0_1 0x24000C 137 #define DI_RUN_VALUE_M1(v) ((v) << 19) 138 #define DI_RUN_RESOLUTION(v) ((v) << 16) 139 #define DI_OFFSET_VALUE(v) ((v) << 3) 140 #define IPU_DI0_SW_GEN1_1 0x240030 141 #define DI_CNT_POLARITY_GEN_EN(v) ((v) << 29) 142 #define DI_CNT_AUTO_RELOAD (1 << 28) 143 #define DI_CNT_CLR_SEL(v) ((v) << 25) 144 #define DI_CNT_DOWN(v) ((v) << 16) 145 #define DI_CNT_POLARITY_TRIGGER_SEL(v) ((v) << 12) 146 #define DI_CNT_POLARITY_CLR_SEL(v) ((v) << 9) 147 #define IPU_DI0_SYNC_AS_GEN 0x240054 148 #define SYNC_AS_GEN_VSYNC_SEL(v) ((v) << 13) 149 #define SYNC_AS_GEN_SYNC_START(v) ((v) << 0) 150 #define IPU_DI0_DW_GEN_0 0x240058 151 #define DW_GEN_DI_ACCESS_SIZE(v) ((v) << 24) 152 #define DW_GEN_DI_COMPONENT_SIZE(v) ((v) << 16) 153 #define DW_GEN_DI_SET_MASK 3 154 #define DW_GEN_DI_PIN_15_SET(v) ((v) << 8) 155 #define IPU_DI0_DW_SET3_0 0x240118 156 #define DW_SET_DATA_CNT_DOWN(v) ((v) << 16) 157 #define DW_SET_DATA_CNT_UP(v) ((v) << 0) 158 #define IPU_DI0_STP_REP 0x240148 159 #define IPU_DI0_POL 0x240164 160 #define DI_POL_DRDY_POLARITY_15 (1 << 4) 161 #define IPU_DI0_SCR_CONF 0x240170 162 163 #define IPU_DI1_GENERAL 0x248000 164 #define IPU_DI1_BS_CLKGEN0 0x248004 165 #define IPU_DI1_BS_CLKGEN1 0x248008 166 #define IPU_DI1_SW_GEN0_1 0x24800C 167 #define IPU_DI1_SW_GEN1_1 0x248030 168 #define IPU_DI1_SYNC_AS_GEN 0x248054 169 #define IPU_DI1_DW_GEN_0 0x248058 170 #define IPU_DI1_POL 0x248164 171 #define IPU_DI1_DW_SET3_0 0x248118 172 #define IPU_DI1_STP_REP 0x248148 173 #define IPU_DI1_SCR_CONF 0x248170 174 #define DMFC_RD_CHAN 0x260000 175 #define DMFC_WR_CHAN 0x260004 176 #define DMFC_WR_CHAN_BURST_SIZE_32 (0 << 6) 177 #define DMFC_WR_CHAN_BURST_SIZE_16 (1 << 6) 178 #define DMFC_WR_CHAN_BURST_SIZE_8 (2 << 6) 179 #define DMFC_WR_CHAN_BURST_SIZE_4 (3 << 6) 180 #define DMFC_WR_CHAN_BURST_SIZE_4 (3 << 6) 181 #define DMFC_WR_CHAN_FIFO_SIZE_128 (2 << 3) 182 #define DMFC_WR_CHAN_DEF 0x260008 183 #define DMFC_WR_CHAN_DEF_WM_CLR_2C(v) ((v) << 29) 184 #define DMFC_WR_CHAN_DEF_WM_CLR_1C(v) ((v) << 21) 185 #define DMFC_WR_CHAN_DEF_WM_CLR_2(v) ((v) << 13) 186 #define DMFC_WR_CHAN_DEF_WM_CLR_1(v) ((v) << 5) 187 #define DMFC_WR_CHAN_DEF_WM_SET_1(v) ((v) << 2) 188 #define DMFC_WR_CHAN_DEF_WM_EN_1 (1 << 1) 189 #define DMFC_DP_CHAN 0x26000C 190 #define DMFC_DP_CHAN_BURST_SIZE_8 2 191 #define DMFC_DP_CHAN_FIFO_SIZE_256 1 192 #define DMFC_DP_CHAN_FIFO_SIZE_128 2 193 #define DMFC_DP_CHAN_BURST_SIZE_5F(v) ((v) << 14) 194 #define DMFC_DP_CHAN_FIFO_SIZE_5F(v) ((v) << 11) 195 #define DMFC_DP_CHAN_ST_ADDR_SIZE_5F(v) ((v) << 8) 196 #define DMFC_DP_CHAN_BURST_SIZE_5B(v) ((v) << 6) 197 #define DMFC_DP_CHAN_FIFO_SIZE_5B(v) ((v) << 3) 198 #define DMFC_DP_CHAN_ST_ADDR_SIZE_5B(v) ((v) << 0) 199 #define DMFC_DP_CHAN_DEF 0x260010 200 #define DMFC_DP_CHAN_DEF_WM_CLR_6F(v) ((v) << 29) 201 #define DMFC_DP_CHAN_DEF_WM_CLR_6B(v) ((v) << 21) 202 #define DMFC_DP_CHAN_DEF_WM_CLR_5F(v) ((v) << 13) 203 #define DMFC_DP_CHAN_DEF_WM_SET_5F(v) ((v) << 10) 204 #define DMFC_DP_CHAN_DEF_WM_EN_5F (1 << 9) 205 #define DMFC_DP_CHAN_DEF_WM_CLR_5B(v) ((v) << 5) 206 #define DMFC_DP_CHAN_DEF_WM_SET_5B(v) ((v) << 2) 207 #define DMFC_DP_CHAN_DEF_WM_EN_5B (1 << 1) 208 #define DMFC_GENERAL_1 0x260014 209 #define DMFC_GENERAL_1_WAIT4EOT_5B (1 << 20) 210 #define DMFC_IC_CTRL 0x26001C 211 #define DMFC_IC_CTRL_DISABLED 0x2 212 213 #define DC_WRITE_CH_CONF_1 0x0025801C 214 #define WRITE_CH_CONF_PROG_CHAN_TYP_MASK (7 << 5) 215 #define WRITE_CH_CONF_PROG_CHAN_NORMAL (4 << 5) 216 #define DC_WRITE_CH_ADDR_1 0x00258020 217 #define DC_WRITE_CH_CONF_5 0x0025805C 218 #define WRITE_CH_CONF_PROG_DISP_ID(v) ((v) << 3) 219 #define WRITE_CH_CONF_PROG_DI_ID(v) ((v) << 2) 220 #define WRITE_CH_CONF_PROG_W_SIZE(v) (v) 221 #define DC_WRITE_CH_ADDR_5 0x00258060 222 #define DC_RL0_CH_5 0x00258064 223 #define DC_GEN 0x002580D4 224 #define DC_GEN_SYNC_PRIORITY (1 << 7) 225 #define DC_GEN_ASYNC (0 << 1) 226 #define DC_GEN_SYNC (2 << 1) 227 #define DC_DISP_CONF2(di) (0x002580E8 + (di) * 4) 228 #define DC_MAP_CONF_0 0x00258108 229 #define DC_MAP_CONF_15 0x00258144 230 #define DC_MAP_CONF_VAL(map) (DC_MAP_CONF_15 + ((map) / 2) * sizeof(uint32_t)) 231 #define MAP_CONF_VAL_MASK 0xffff 232 #define DC_MAP_CONF_PTR(ptr) (DC_MAP_CONF_0 + ((ptr) / 2) * sizeof(uint32_t)) 233 #define MAP_CONF_PTR_MASK 0x1f 234 235 #define DI_COUNTER_INT_HSYNC 1 236 #define DI_COUNTER_HSYNC 2 237 #define DI_COUNTER_VSYNC 3 238 #define DI_COUNTER_AD_0 4 239 #define DI_COUNTER_AD_1 5 240 241 #define DI_SYNC_NONE 0 242 #define DI_SYNC_CLK 1 243 #define DI_SYNC_COUNTER(c) ((c) + 1) 244 245 struct ipu_cpmem_word { 246 uint32_t data[5]; 247 uint32_t padding[3]; 248 }; 249 250 struct ipu_cpmem_ch_param { 251 struct ipu_cpmem_word word[2]; 252 }; 253 254 #define CH_PARAM_RESET(param) memset(param, 0, sizeof(*param)) 255 #define IPU_READ_CH_PARAM(_sc, ch, param) bus_read_region_4( \ 256 (_sc)->sc_mem_res, CPMEM_BASE + ch * (sizeof(*param)),\ 257 (uint32_t*)param, sizeof(*param) / 4) 258 #define IPU_WRITE_CH_PARAM(_sc, ch, param) bus_write_region_4( \ 259 (_sc)->sc_mem_res, CPMEM_BASE + ch * (sizeof(*param)),\ 260 (uint32_t*)param, sizeof(*param) / 4) 261 262 #define CH_PARAM_SET_FW(param, v) ipu_ch_param_set_value((param), \ 263 0, 125, 13, (v)) 264 #define CH_PARAM_SET_FH(param, v) ipu_ch_param_set_value((param), \ 265 0, 138, 12, (v)) 266 #define CH_PARAM_SET_SLY(param, v) ipu_ch_param_set_value((param), \ 267 1, 102, 14, (v)) 268 #define CH_PARAM_SET_EBA0(param, v) ipu_ch_param_set_value((param), \ 269 1, 0, 29, (v)) 270 #define CH_PARAM_SET_EBA1(param, v) ipu_ch_param_set_value((param), \ 271 1, 29, 29, (v)) 272 #define CH_PARAM_SET_BPP(param, v) ipu_ch_param_set_value((param), \ 273 0, 107, 3, (v)) 274 #define CH_PARAM_SET_PFS(param, v) ipu_ch_param_set_value((param), \ 275 1, 85, 4, (v)) 276 #define CH_PARAM_SET_NPB(param, v) ipu_ch_param_set_value((param), \ 277 1, 78, 7, (v)) 278 #define CH_PARAM_SET_UBO(param, v) ipu_ch_param_set_value((param), \ 279 0, 46, 22, (v)) 280 #define CH_PARAM_SET_VBO(param, v) ipu_ch_param_set_value((param), \ 281 0, 68, 22, (v)) 282 283 #define CH_PARAM_SET_RED_WIDTH(param, v) ipu_ch_param_set_value((param), \ 284 1, 116, 3, (v)) 285 #define CH_PARAM_SET_RED_OFFSET(param, v) ipu_ch_param_set_value((param), \ 286 1, 128, 5, (v)) 287 288 #define CH_PARAM_SET_GREEN_WIDTH(param, v) ipu_ch_param_set_value((param), \ 289 1, 119, 3, (v)) 290 #define CH_PARAM_SET_GREEN_OFFSET(param, v) ipu_ch_param_set_value((param), \ 291 1, 133, 5, (v)) 292 293 #define CH_PARAM_SET_BLUE_WIDTH(param, v) ipu_ch_param_set_value((param), \ 294 1, 122, 3, (v)) 295 #define CH_PARAM_SET_BLUE_OFFSET(param, v) ipu_ch_param_set_value((param), \ 296 1, 138, 5, (v)) 297 298 #define CH_PARAM_SET_ALPHA_WIDTH(param, v) ipu_ch_param_set_value((param), \ 299 1, 125, 3, (v)) 300 #define CH_PARAM_SET_ALPHA_OFFSET(param, v) ipu_ch_param_set_value((param), \ 301 1, 143, 5, (v)) 302 303 #define CH_PARAM_GET_FW(param) ipu_ch_param_get_value((param), \ 304 0, 125, 13) 305 #define CH_PARAM_GET_FH(param) ipu_ch_param_get_value((param), \ 306 0, 138, 12) 307 #define CH_PARAM_GET_SLY(param) ipu_ch_param_get_value((param), \ 308 1, 102, 14) 309 #define CH_PARAM_GET_EBA0(param) ipu_ch_param_get_value((param), \ 310 1, 0, 29) 311 #define CH_PARAM_GET_EBA1(param) ipu_ch_param_get_value((param), \ 312 1, 29, 29) 313 #define CH_PARAM_GET_BPP(param) ipu_ch_param_get_value((param), \ 314 0, 107, 3) 315 #define CH_PARAM_GET_PFS(param) ipu_ch_param_get_value((param), \ 316 1, 85, 4) 317 #define CH_PARAM_GET_NPB(param) ipu_ch_param_get_value((param), \ 318 1, 78, 7) 319 #define CH_PARAM_GET_UBO(param) ipu_ch_param_get_value((param), \ 320 0, 46, 22) 321 #define CH_PARAM_GET_VBO(param) ipu_ch_param_get_value((param), \ 322 0, 68, 22) 323 324 #define CH_PARAM_GET_RED_WIDTH(param) ipu_ch_param_get_value((param), \ 325 1, 116, 3) 326 #define CH_PARAM_GET_RED_OFFSET(param) ipu_ch_param_get_value((param), \ 327 1, 128, 5) 328 329 #define CH_PARAM_GET_GREEN_WIDTH(param) ipu_ch_param_get_value((param), \ 330 1, 119, 3) 331 #define CH_PARAM_GET_GREEN_OFFSET(param) ipu_ch_param_get_value((param), \ 332 1, 133, 5) 333 334 #define CH_PARAM_GET_BLUE_WIDTH(param) ipu_ch_param_get_value((param), \ 335 1, 122, 3) 336 #define CH_PARAM_GET_BLUE_OFFSET(param) ipu_ch_param_get_value((param), \ 337 1, 138, 5) 338 339 #define CH_PARAM_GET_ALPHA_WIDTH(param) ipu_ch_param_get_value((param), \ 340 1, 125, 3) 341 #define CH_PARAM_GET_ALPHA_OFFSET(param) ipu_ch_param_get_value((param), \ 342 1, 143, 5) 343 344 #define IPU_PIX_FORMAT_BPP_32 0 345 #define IPU_PIX_FORMAT_BPP_24 1 346 #define IPU_PIX_FORMAT_BPP_18 2 347 #define IPU_PIX_FORMAT_BPP_16 3 348 #define IPU_PIX_FORMAT_BPP_12 4 349 #define IPU_PIX_FORMAT_BPP_8 5 350 #define IPU_PIX_FORMAT_BPP_ 351 352 #define IPU_PIX_FORMAT_RGB 7 353 354 enum dc_event_t { 355 DC_EVENT_NF = 0, 356 DC_EVENT_NL, 357 DC_EVENT_EOF, 358 DC_EVENT_NFIELD, 359 DC_EVENT_EOL, 360 DC_EVENT_EOFIELD, 361 DC_EVENT_NEW_ADDR, 362 DC_EVENT_NEW_CHAN, 363 DC_EVENT_NEW_DATA 364 }; 365 366 struct ipu_softc { 367 device_t sc_dev; 368 struct resource *sc_mem_res; 369 int sc_mem_rid; 370 struct resource *sc_irq_res; 371 int sc_irq_rid; 372 void *sc_intr_hl; 373 struct mtx sc_mtx; 374 struct fb_info sc_fb_info; 375 const struct videomode *sc_mode; 376 377 /* Framebuffer */ 378 bus_dma_tag_t sc_dma_tag; 379 bus_dmamap_t sc_dma_map; 380 size_t sc_fb_size; 381 bus_addr_t sc_fb_phys; 382 uint8_t *sc_fb_base; 383 384 /* HDMI */ 385 eventhandler_tag sc_hdmi_evh; 386 }; 387 388 static void 389 ipu_dmamap_cb(void *arg, bus_dma_segment_t *segs, int nseg, int err) 390 { 391 bus_addr_t *addr; 392 393 if (err) 394 return; 395 396 addr = (bus_addr_t*)arg; 397 *addr = segs[0].ds_addr; 398 } 399 400 static void 401 ipu_ch_param_set_value(struct ipu_cpmem_ch_param *param, 402 int word, unsigned int offset, int len, uint32_t value) 403 { 404 uint32_t datapos, bitpos, mask; 405 uint32_t data, data2; 406 407 KASSERT((len <= 32), ("%s: field len is more than 32", __func__)); 408 409 datapos = offset / 32; 410 bitpos = offset % 32; 411 412 mask = (1 << len) - 1; 413 data = param->word[word].data[datapos]; 414 data &= ~(mask << bitpos); 415 data |= (value << bitpos); 416 param->word[word].data[datapos] = data; 417 418 if ((bitpos + len) > 32) { 419 len = bitpos + len - 32; 420 mask = (1UL << len) - 1; 421 data2 = param->word[word].data[datapos + 1]; 422 data2 &= mask; 423 data2 |= (value >> (32 - bitpos)); 424 param->word[word].data[datapos + 1] = data2; 425 } 426 } 427 428 #ifdef DEBUG 429 static uint32_t 430 ipu_ch_param_get_value(struct ipu_cpmem_ch_param *param, 431 int word, unsigned int offset, int len) 432 { 433 uint32_t datapos, bitpos, mask; 434 uint32_t data, data2; 435 436 KASSERT((len <= 32), ("%s: field len is more than 32", __func__)); 437 438 datapos = offset / 32; 439 bitpos = offset % 32; 440 mask = (1UL << len) - 1; 441 data = param->word[word].data[datapos]; 442 data = data >> bitpos; 443 data &= mask; 444 if ((bitpos + len) > 32) { 445 len = bitpos + len - 32; 446 mask = (1UL << len) - 1; 447 data2 = param->word[word].data[datapos + 1]; 448 data2 &= mask; 449 data |= (data2 << (32 - bitpos)); 450 } 451 452 return (data); 453 } 454 455 static void 456 ipu_print_channel(struct ipu_cpmem_ch_param *param) 457 { 458 int offset0[] = {0, 10, 19, 32, 44, 45, 46, 68, 90, 94, 95, 113, 114, 117, 119, 120, 121, 122, 123, 124, 125, 138, 150, 151, -1}; 459 int offset1[] = {0, 29, 58, 78, 85, 89, 90, 93, 95, 102, 116, 119, 122, 125, 128, 133, 138, 143, 148, 149, 150, -1}; 460 printf("WORD0: %08x %08x %08x %08x %08x\n", 461 param->word[0].data[0], param->word[0].data[1], 462 param->word[0].data[2], param->word[0].data[3], 463 param->word[0].data[4]); 464 printf("WORD1: %08x %08x %08x %08x %08x\n", 465 param->word[1].data[0], param->word[1].data[1], 466 param->word[1].data[2], param->word[1].data[3], 467 param->word[1].data[4]); 468 469 for (int i = 0; offset0[i + 1] != -1; i++) { 470 int len = offset0[i + 1] - offset0[i]; 471 printf("W0[%d:%d] = %d\n", offset0[i], 472 offset0[i] + len - 1, 473 ipu_ch_param_get_value(param, 0, offset0[i], len) 474 ); 475 } 476 477 for (int i = 0; offset1[i + 1] != -1; i++) { 478 int len = offset1[i + 1] - offset1[i]; 479 printf("W1[%d:%d] = %d\n", offset1[i], 480 offset1[i] + len - 1, 481 ipu_ch_param_get_value(param, 1, offset1[i], len) 482 ); 483 } 484 485 printf("FW: %d\n", CH_PARAM_GET_FW(param)); 486 printf("FH: %d\n", CH_PARAM_GET_FH(param)); 487 printf("SLY: %d\n", CH_PARAM_GET_SLY(param)); 488 printf("EBA0: 0x%08x\n", CH_PARAM_GET_EBA0(param)); 489 printf("EBA1: 0x%08x\n", CH_PARAM_GET_EBA1(param)); 490 printf("BPP: %d\n", CH_PARAM_GET_BPP(param)); 491 printf("PFS: %d\n", CH_PARAM_GET_PFS(param)); 492 printf("NPB: %d\n", CH_PARAM_GET_NPB(param)); 493 printf("UBO: %d\n", CH_PARAM_GET_UBO(param)); 494 printf("VBO: %d\n", CH_PARAM_GET_VBO(param)); 495 printf("RED: %d bits @%d\n", CH_PARAM_GET_RED_WIDTH(param) + 1, 496 CH_PARAM_GET_RED_OFFSET(param)); 497 printf("GREEN: %d bits @%d\n", CH_PARAM_GET_GREEN_WIDTH(param) + 1, 498 CH_PARAM_GET_GREEN_OFFSET(param)); 499 printf("BLUE: %d bits @%d\n", CH_PARAM_GET_BLUE_WIDTH(param) + 1, 500 CH_PARAM_GET_BLUE_OFFSET(param)); 501 printf("ALPHA: %d bits @%d\n", CH_PARAM_GET_ALPHA_WIDTH(param) + 1, 502 CH_PARAM_GET_ALPHA_OFFSET(param)); 503 } 504 #endif 505 506 static void 507 ipu_di_enable(struct ipu_softc *sc, int di) 508 { 509 uint32_t flag, reg; 510 511 flag = di ? DISP_GEN_DI1_CNTR_RELEASE : DISP_GEN_DI0_CNTR_RELEASE; 512 reg = IPU_READ4(sc, IPU_DISP_GEN); 513 reg |= flag; 514 IPU_WRITE4(sc, IPU_DISP_GEN, reg); 515 } 516 517 static void 518 ipu_config_wave_gen_0(struct ipu_softc *sc, int di, 519 int wave_gen, int run_value, int run_res, 520 int offset_value, int offset_res) 521 { 522 uint32_t addr, reg; 523 524 addr = (di ? IPU_DI1_SW_GEN0_1 : IPU_DI0_SW_GEN0_1) 525 + (wave_gen - 1) * sizeof(uint32_t); 526 reg = DI_RUN_VALUE_M1(run_value) | 527 DI_RUN_RESOLUTION(run_res) | 528 DI_OFFSET_VALUE(offset_value) | offset_res; 529 IPU_WRITE4(sc, addr, reg); 530 } 531 532 static void 533 ipu_config_wave_gen_1(struct ipu_softc *sc, int di, int wave_gen, 534 int repeat_count, int cnt_clr_src, 535 int cnt_polarity_gen_en, 536 int cnt_polarity_clr_src, 537 int cnt_polarity_trigger_src, 538 int cnt_up, int cnt_down) 539 { 540 uint32_t addr, reg; 541 542 addr = (di ? IPU_DI1_SW_GEN1_1 : IPU_DI0_SW_GEN1_1) 543 + (wave_gen - 1) * sizeof(uint32_t); 544 reg = DI_CNT_POLARITY_GEN_EN(cnt_polarity_gen_en) | 545 DI_CNT_CLR_SEL(cnt_clr_src) | 546 DI_CNT_POLARITY_TRIGGER_SEL(cnt_polarity_trigger_src) | 547 DI_CNT_POLARITY_CLR_SEL(cnt_polarity_clr_src); 548 reg |= DI_CNT_DOWN(cnt_down) | cnt_up; 549 if (repeat_count == 0) 550 reg |= DI_CNT_AUTO_RELOAD; 551 IPU_WRITE4(sc, addr, reg); 552 553 addr = (di ? IPU_DI1_STP_REP : IPU_DI0_STP_REP) 554 + (wave_gen - 1) / 2 * sizeof(uint32_t); 555 reg = IPU_READ4(sc, addr); 556 if (wave_gen % 2) { 557 reg &= ~(0xffff); 558 reg |= repeat_count; 559 } 560 else { 561 reg &= ~(0xffff << 16); 562 reg |= (repeat_count << 16); 563 } 564 IPU_WRITE4(sc, addr, reg); 565 } 566 567 static void 568 ipu_reset_wave_gen(struct ipu_softc *sc, int di, 569 int wave_gen) 570 { 571 uint32_t addr, reg; 572 573 addr = (di ? IPU_DI1_SW_GEN0_1 : IPU_DI0_SW_GEN0_1) 574 + (wave_gen - 1) * sizeof(uint32_t); 575 IPU_WRITE4(sc, addr, 0); 576 577 addr = (di ? IPU_DI1_SW_GEN1_1 : IPU_DI0_SW_GEN1_1) 578 + (wave_gen - 1) * sizeof(uint32_t); 579 IPU_WRITE4(sc, addr, 0); 580 581 addr = (di ? IPU_DI1_STP_REP : IPU_DI0_STP_REP) 582 + (wave_gen - 1) / 2 * sizeof(uint32_t); 583 reg = IPU_READ4(sc, addr); 584 if (wave_gen % 2) 585 reg &= ~(0xffff); 586 else 587 reg &= ~(0xffff << 16); 588 IPU_WRITE4(sc, addr, reg); 589 } 590 591 static void 592 ipu_init_microcode_template(struct ipu_softc *sc, int di, int map) 593 { 594 uint32_t addr; 595 uint32_t w1, w2; 596 int i, word; 597 int glue; 598 599 word = di ? 2 : 5; 600 601 for (i = 0; i < 3; i++) { 602 if (i == 0) 603 glue = GLUELOGIC_KEEP_ASSERTED; 604 else if (i == 1) 605 glue = GLUELOGIC_KEEP_NEGATED; 606 else if (i == 2) 607 glue = 0; 608 609 w1 = TEMPLATE_SYNC(5) | 610 TEMPLATE_GLUELOGIC(glue) | 611 TEMPLATE_WAVEFORM(1) | /* wave unit 0 */ 612 TEMPLATE_MAPPING(map + 1); 613 /* operand is zero */ 614 615 /* Write data to DI and Hold data in register */ 616 w2 = TEMPLATE_OPCODE(OPCODE_WROD) | 617 TEMPLATE_STOP; 618 619 addr = DC_TEMPL_BASE + (word + i) * 2 * sizeof(uint32_t); 620 IPU_WRITE4(sc, addr, w1); 621 IPU_WRITE4(sc, addr + sizeof(uint32_t), w2); 622 } 623 } 624 625 static uint32_t 626 ipu_calc_divisor(uint32_t reference, uint32_t freq) 627 { 628 uint32_t div, i; 629 uint32_t delta, min_delta; 630 631 min_delta = freq; 632 div = 255; 633 634 for (i = 1; i < 255; i++) { 635 delta = abs(reference/i - freq); 636 if (delta < min_delta) { 637 div = i; 638 min_delta = delta; 639 } 640 } 641 642 return (div); 643 } 644 645 static void 646 ipu_config_timing(struct ipu_softc *sc, int di) 647 { 648 uint32_t div; 649 uint32_t di_scr_conf; 650 uint32_t gen_offset, gen; 651 uint32_t as_gen_offset, as_gen; 652 uint32_t dw_gen_offset, dw_gen; 653 uint32_t dw_set_offset, dw_set; 654 uint32_t bs_clkgen_offset; 655 int map; 656 uint32_t freq; 657 658 freq = sc->sc_mode->dot_clock * 1000; 659 660 div = ipu_calc_divisor(imx_ccm_ipu_hz(), freq); 661 map = 0; 662 663 bs_clkgen_offset = di ? IPU_DI1_BS_CLKGEN0 : IPU_DI0_BS_CLKGEN0; 664 IPU_WRITE4(sc, bs_clkgen_offset, DI_BS_CLKGEN0(div, 0)); 665 /* half of the divider */ 666 IPU_WRITE4(sc, bs_clkgen_offset + 4, DI_BS_CLKGEN1_DOWN(div / 2, div % 2)); 667 668 /* Setup wave generator */ 669 dw_gen_offset = di ? IPU_DI1_DW_GEN_0 : IPU_DI0_DW_GEN_0; 670 dw_gen = DW_GEN_DI_ACCESS_SIZE(div - 1) | DW_GEN_DI_COMPONENT_SIZE(div - 1); 671 dw_gen &= ~DW_GEN_DI_PIN_15_SET(DW_GEN_DI_SET_MASK); 672 dw_gen |= DW_GEN_DI_PIN_15_SET(3); /* set 3*/ 673 IPU_WRITE4(sc, dw_gen_offset, dw_gen); 674 675 dw_set_offset = di ? IPU_DI1_DW_SET3_0 : IPU_DI0_DW_SET3_0; 676 dw_set = DW_SET_DATA_CNT_DOWN(div * 2) | DW_SET_DATA_CNT_UP(0); 677 IPU_WRITE4(sc, dw_set_offset, dw_set); 678 679 /* DI_COUNTER_INT_HSYNC */ 680 ipu_config_wave_gen_0(sc, di, DI_COUNTER_INT_HSYNC, 681 sc->sc_mode->htotal - 1, DI_SYNC_CLK, 0, DI_SYNC_NONE); 682 ipu_config_wave_gen_1(sc, di, DI_COUNTER_INT_HSYNC, 683 0, DI_SYNC_NONE, 0, DI_SYNC_NONE, DI_SYNC_NONE, 0, 0); 684 685 /* DI_COUNTER_HSYNC */ 686 ipu_config_wave_gen_0(sc, di, DI_COUNTER_HSYNC, 687 sc->sc_mode->htotal - 1, DI_SYNC_CLK, 0, DI_SYNC_CLK); 688 ipu_config_wave_gen_1(sc, di, DI_COUNTER_HSYNC, 689 0, DI_SYNC_NONE, 1, DI_SYNC_NONE, DI_SYNC_CLK, 690 0, MODE_HSW(sc->sc_mode) * 2); 691 692 /* DI_COUNTER_VSYNC */ 693 ipu_config_wave_gen_0(sc, di, DI_COUNTER_VSYNC, 694 sc->sc_mode->vtotal - 1, DI_SYNC_COUNTER(DI_COUNTER_INT_HSYNC), 695 0, DI_SYNC_NONE); 696 ipu_config_wave_gen_1(sc, di, DI_COUNTER_VSYNC, 697 0, DI_SYNC_NONE, 1, DI_SYNC_NONE, 698 DI_SYNC_COUNTER(DI_COUNTER_INT_HSYNC), 699 0, MODE_VSW(sc->sc_mode) * 2); 700 701 di_scr_conf = di ? IPU_DI1_SCR_CONF : IPU_DI0_SCR_CONF; 702 IPU_WRITE4(sc, di_scr_conf, sc->sc_mode->vtotal - 1); 703 704 /* TODO: update DI_SCR_CONF */ 705 706 /* Active Data 0 */ 707 ipu_config_wave_gen_0(sc, di, DI_COUNTER_AD_0, 708 0, DI_SYNC_COUNTER(DI_COUNTER_HSYNC), 709 MODE_VSW(sc->sc_mode) + MODE_VFP(sc->sc_mode), DI_SYNC_COUNTER(DI_COUNTER_HSYNC)); 710 ipu_config_wave_gen_1(sc, di, DI_COUNTER_AD_0, 711 sc->sc_mode->vdisplay, DI_SYNC_COUNTER(DI_COUNTER_VSYNC), 712 0, DI_SYNC_NONE, DI_SYNC_NONE, 0, 0); 713 714 ipu_config_wave_gen_0(sc, di, DI_COUNTER_AD_1, 715 0, DI_SYNC_CLK, MODE_HSW(sc->sc_mode) + MODE_HFP(sc->sc_mode), DI_SYNC_CLK); 716 ipu_config_wave_gen_1(sc, di, DI_COUNTER_AD_1, 717 sc->sc_mode->hdisplay, DI_SYNC_COUNTER(DI_COUNTER_AD_0), 718 0, DI_SYNC_NONE, DI_SYNC_NONE, 0, 0); 719 720 ipu_reset_wave_gen(sc, di, 6); 721 ipu_reset_wave_gen(sc, di, 7); 722 ipu_reset_wave_gen(sc, di, 8); 723 ipu_reset_wave_gen(sc, di, 9); 724 725 ipu_init_microcode_template(sc, di, map); 726 727 gen_offset = di ? IPU_DI1_GENERAL : IPU_DI0_GENERAL; 728 gen = IPU_READ4(sc, gen_offset); 729 730 if (sc->sc_mode->flags & VID_NHSYNC) 731 gen &= ~DI_GENERAL_POLARITY_2; 732 else /* active high */ 733 gen |= DI_GENERAL_POLARITY_2; 734 735 if (sc->sc_mode->flags & VID_NVSYNC) 736 gen &= ~DI_GENERAL_POLARITY_3; 737 else /* active high */ 738 gen |= DI_GENERAL_POLARITY_3; 739 740 if (MODE_PIXEL_CLOCK_INVERT) 741 gen &= ~DI_GENERAL_POL_CLK; 742 else 743 gen |= DI_GENERAL_POL_CLK; 744 745 /* Use LDB clock to drive pixel clock */ 746 gen |= DI_CLOCK_EXTERNAL; 747 748 IPU_WRITE4(sc, gen_offset, gen); 749 750 as_gen_offset = di ? IPU_DI1_SYNC_AS_GEN : IPU_DI0_SYNC_AS_GEN; 751 as_gen = SYNC_AS_GEN_VSYNC_SEL(DI_COUNTER_VSYNC - 1) | 752 SYNC_AS_GEN_SYNC_START(2); 753 IPU_WRITE4(sc, as_gen_offset, as_gen); 754 755 IPU_WRITE4(sc, (di ? IPU_DI1_POL : IPU_DI0_POL), DI_POL_DRDY_POLARITY_15); 756 757 IPU_WRITE4(sc, DC_DISP_CONF2(di), sc->sc_mode->hdisplay); 758 } 759 760 static void 761 ipu_dc_enable(struct ipu_softc *sc) 762 { 763 uint32_t conf; 764 765 /* channel 1 uses DI1 */ 766 IPU_WRITE4(sc, DC_WRITE_CH_CONF_1, WRITE_CH_CONF_PROG_DI_ID(1)); 767 768 conf = IPU_READ4(sc, DC_WRITE_CH_CONF_5); 769 conf &= ~WRITE_CH_CONF_PROG_CHAN_TYP_MASK; 770 conf |= WRITE_CH_CONF_PROG_CHAN_NORMAL; 771 IPU_WRITE4(sc, DC_WRITE_CH_CONF_5, conf); 772 } 773 774 static void 775 ipu_dc_link_event(struct ipu_softc *sc, int event, int addr, int priority) 776 { 777 uint32_t reg; 778 int offset; 779 int shift; 780 781 if (event % 2) 782 shift = 16; 783 else 784 shift = 0; 785 786 offset = DC_RL0_CH_5 + (event / 2) * sizeof(uint32_t); 787 788 reg = IPU_READ4(sc, offset); 789 reg &= ~(0xFFFF << shift); 790 reg |= ((addr << 8) | priority) << shift; 791 IPU_WRITE4(sc, offset, reg); 792 } 793 794 static void 795 ipu_dc_setup_map(struct ipu_softc *sc, int map, 796 int byte, int offset, int mask) 797 { 798 uint32_t reg, shift, ptr; 799 800 ptr = map * 3 + byte; 801 802 reg = IPU_READ4(sc, DC_MAP_CONF_VAL(ptr)); 803 if (ptr & 1) 804 shift = 16; 805 else 806 shift = 0; 807 reg &= ~(0xffff << shift); 808 reg |= ((offset << 8) | mask) << shift; 809 IPU_WRITE4(sc, DC_MAP_CONF_VAL(ptr), reg); 810 811 reg = IPU_READ4(sc, DC_MAP_CONF_PTR(map)); 812 if (map & 1) 813 shift = 16 + 5 * byte; 814 else 815 shift = 5 * byte; 816 reg &= ~(MAP_CONF_PTR_MASK << shift); 817 reg |= (ptr) << shift; 818 IPU_WRITE4(sc, DC_MAP_CONF_PTR(map), reg); 819 } 820 821 static void 822 ipu_dc_reset_map(struct ipu_softc *sc, int map) 823 { 824 uint32_t reg, shift; 825 826 reg = IPU_READ4(sc, DC_MAP_CONF_VAL(map)); 827 if (map & 1) 828 shift = 16; 829 else 830 shift = 0; 831 reg &= ~(MAP_CONF_VAL_MASK << shift); 832 IPU_WRITE4(sc, DC_MAP_CONF_VAL(map), reg); 833 } 834 835 static void 836 ipu_dc_init(struct ipu_softc *sc, int di_port) 837 { 838 int addr; 839 uint32_t conf; 840 841 if (di_port) 842 addr = 2; 843 else 844 addr = 5; 845 846 ipu_dc_link_event(sc, DC_EVENT_NL, addr, 3); 847 ipu_dc_link_event(sc, DC_EVENT_EOL, addr + 1, 2); 848 ipu_dc_link_event(sc, DC_EVENT_NEW_DATA, addr + 2, 1); 849 ipu_dc_link_event(sc, DC_EVENT_NF, 0, 0); 850 ipu_dc_link_event(sc, DC_EVENT_NFIELD, 0, 0); 851 ipu_dc_link_event(sc, DC_EVENT_EOF, 0, 0); 852 ipu_dc_link_event(sc, DC_EVENT_EOFIELD, 0, 0); 853 ipu_dc_link_event(sc, DC_EVENT_NEW_CHAN, 0, 0); 854 ipu_dc_link_event(sc, DC_EVENT_NEW_ADDR, 0, 0); 855 856 conf = WRITE_CH_CONF_PROG_W_SIZE(0x02) | 857 WRITE_CH_CONF_PROG_DISP_ID(DI_PORT) | 858 WRITE_CH_CONF_PROG_DI_ID(DI_PORT); 859 860 IPU_WRITE4(sc, DC_WRITE_CH_CONF_5, conf); 861 IPU_WRITE4(sc, DC_WRITE_CH_ADDR_5, 0x00000000); 862 IPU_WRITE4(sc, DC_GEN, DC_GEN_SYNC_PRIORITY | DC_GEN_SYNC); /* High priority, sync */ 863 } 864 865 static void 866 ipu_init_buffer(struct ipu_softc *sc) 867 { 868 struct ipu_cpmem_ch_param param; 869 uint32_t stride; 870 uint32_t reg, db_mode_sel, cur_buf; 871 872 stride = sc->sc_mode->hdisplay * MODE_BPP / 8; 873 874 /* init channel parameters */ 875 CH_PARAM_RESET(¶m); 876 /* XXX: interlaced modes are not supported yet */ 877 CH_PARAM_SET_FW(¶m, sc->sc_mode->hdisplay - 1); 878 CH_PARAM_SET_FH(¶m, sc->sc_mode->vdisplay - 1); 879 CH_PARAM_SET_SLY(¶m, stride - 1); 880 881 CH_PARAM_SET_EBA0(¶m, (sc->sc_fb_phys >> 3)); 882 CH_PARAM_SET_EBA1(¶m, (sc->sc_fb_phys >> 3)); 883 884 CH_PARAM_SET_BPP(¶m, IPU_PIX_FORMAT_BPP_16); 885 CH_PARAM_SET_PFS(¶m, IPU_PIX_FORMAT_RGB); 886 /* 16 pixels per burst access */ 887 CH_PARAM_SET_NPB(¶m, 16 - 1); 888 889 CH_PARAM_SET_RED_OFFSET(¶m, 0); 890 CH_PARAM_SET_RED_WIDTH(¶m, 5 - 1); 891 CH_PARAM_SET_GREEN_OFFSET(¶m, 5); 892 CH_PARAM_SET_GREEN_WIDTH(¶m, 6 - 1); 893 CH_PARAM_SET_BLUE_OFFSET(¶m, 11); 894 CH_PARAM_SET_BLUE_WIDTH(¶m, 5 - 1); 895 CH_PARAM_SET_ALPHA_OFFSET(¶m, 16); 896 CH_PARAM_SET_ALPHA_WIDTH(¶m, 8 - 1); 897 898 CH_PARAM_SET_UBO(¶m, 0); 899 CH_PARAM_SET_VBO(¶m, 0); 900 901 IPU_WRITE_CH_PARAM(sc, DMA_CHANNEL, ¶m); 902 #ifdef DEBUG 903 ipu_print_channel(¶m); 904 #endif 905 906 /* init DMFC */ 907 IPU_WRITE4(sc, DMFC_IC_CTRL, DMFC_IC_CTRL_DISABLED); 908 /* High resolution DP */ 909 IPU_WRITE4(sc, DMFC_WR_CHAN, DMFC_WR_CHAN_BURST_SIZE_8 | 910 DMFC_WR_CHAN_FIFO_SIZE_128); 911 IPU_WRITE4(sc, DMFC_WR_CHAN_DEF, DMFC_WR_CHAN_DEF_WM_CLR_2C(1) | 912 DMFC_WR_CHAN_DEF_WM_CLR_1C(1) | 913 DMFC_WR_CHAN_DEF_WM_CLR_2(1) | 914 DMFC_WR_CHAN_DEF_WM_CLR_1(7) | 915 DMFC_WR_CHAN_DEF_WM_SET_1(5) | 916 DMFC_WR_CHAN_DEF_WM_EN_1); 917 918 IPU_WRITE4(sc, DMFC_DP_CHAN, 919 DMFC_DP_CHAN_BURST_SIZE_5F(DMFC_DP_CHAN_BURST_SIZE_8) | 920 DMFC_DP_CHAN_FIFO_SIZE_5F(DMFC_DP_CHAN_FIFO_SIZE_128) | 921 DMFC_DP_CHAN_ST_ADDR_SIZE_5F(6) /* segment 6 */ | 922 DMFC_DP_CHAN_BURST_SIZE_5B(DMFC_DP_CHAN_BURST_SIZE_8) | 923 DMFC_DP_CHAN_FIFO_SIZE_5B(DMFC_DP_CHAN_FIFO_SIZE_256) | 924 DMFC_DP_CHAN_ST_ADDR_SIZE_5B(2) /* segment 2 */); 925 926 IPU_WRITE4(sc, DMFC_DP_CHAN_DEF, DMFC_DP_CHAN_DEF_WM_CLR_6F(1) | 927 DMFC_DP_CHAN_DEF_WM_CLR_6B(1) | 928 DMFC_DP_CHAN_DEF_WM_CLR_5F(7) | 929 DMFC_DP_CHAN_DEF_WM_SET_5F(5) | 930 DMFC_DP_CHAN_DEF_WM_EN_5F | 931 DMFC_DP_CHAN_DEF_WM_CLR_5B(7) | 932 DMFC_DP_CHAN_DEF_WM_SET_5B(5) | 933 DMFC_DP_CHAN_DEF_WM_EN_5B); 934 935 reg = IPU_READ4(sc, DMFC_GENERAL_1); 936 reg &= ~(DMFC_GENERAL_1_WAIT4EOT_5B); 937 IPU_WRITE4(sc, DMFC_GENERAL_1, reg); 938 939 /* XXX: set priority? */ 940 941 /* Set single buffer mode */ 942 if (DMA_CHANNEL < 32) { 943 db_mode_sel = IPU_CH_DB_MODE_SEL_0; 944 cur_buf = IPU_CUR_BUF_0; 945 } else { 946 db_mode_sel = IPU_CH_DB_MODE_SEL_1; 947 cur_buf = IPU_CUR_BUF_1; 948 } 949 950 reg = IPU_READ4(sc, db_mode_sel); 951 reg |= (1UL << (DMA_CHANNEL & 0x1f)); 952 IPU_WRITE4(sc, db_mode_sel, reg); 953 954 IPU_WRITE4(sc, cur_buf, (1UL << (DMA_CHANNEL & 0x1f))); 955 } 956 957 static int 958 ipu_init(struct ipu_softc *sc) 959 { 960 uint32_t reg, off; 961 int i, err; 962 size_t dma_size; 963 964 IPU_WRITE4(sc, IPU_CONF, DI_PORT ? IPU_CONF_DI1_EN : IPU_CONF_DI0_EN); 965 966 IPU_WRITE4(sc, IPU_MEM_RST, IPU_MEM_RST_ALL); 967 i = 1000; 968 while (i-- > 0) { 969 if (!(IPU_READ4(sc, IPU_MEM_RST) & IPU_MEM_RST_START)) 970 break; 971 DELAY(1); 972 } 973 974 if (i <= 0) { 975 err = ETIMEDOUT; 976 device_printf(sc->sc_dev, "timeout while resetting memory\n"); 977 goto fail; 978 } 979 980 ipu_dc_reset_map(sc, 0); 981 ipu_dc_setup_map(sc, 0, 0, 7, 0xff); 982 ipu_dc_setup_map(sc, 0, 1, 15, 0xff); 983 ipu_dc_setup_map(sc, 0, 2, 23, 0xff); 984 985 dma_size = round_page(sc->sc_mode->hdisplay * sc->sc_mode->vdisplay * (MODE_BPP / 8)); 986 987 /* 988 * Now allocate framebuffer memory 989 */ 990 err = bus_dma_tag_create( 991 bus_get_dma_tag(sc->sc_dev), 992 4, 0, /* alignment, boundary */ 993 BUS_SPACE_MAXADDR_32BIT, /* lowaddr */ 994 BUS_SPACE_MAXADDR, /* highaddr */ 995 NULL, NULL, /* filter, filterarg */ 996 dma_size, 1, /* maxsize, nsegments */ 997 dma_size, 0, /* maxsegsize, flags */ 998 NULL, NULL, /* lockfunc, lockarg */ 999 &sc->sc_dma_tag); 1000 if (err) 1001 goto fail; 1002 1003 err = bus_dmamem_alloc(sc->sc_dma_tag, (void **)&sc->sc_fb_base, 1004 BUS_DMA_COHERENT | BUS_DMA_ZERO, &sc->sc_dma_map); 1005 1006 if (err) { 1007 device_printf(sc->sc_dev, "cannot allocate framebuffer\n"); 1008 goto fail; 1009 } 1010 1011 err = bus_dmamap_load(sc->sc_dma_tag, sc->sc_dma_map, sc->sc_fb_base, 1012 dma_size, ipu_dmamap_cb, &sc->sc_fb_phys, BUS_DMA_NOWAIT); 1013 1014 if (err) { 1015 device_printf(sc->sc_dev, "cannot load DMA map\n"); 1016 goto fail; 1017 } 1018 1019 /* Calculate actual FB Size */ 1020 sc->sc_fb_size = sc->sc_mode->hdisplay * sc->sc_mode->vdisplay * MODE_BPP / 8; 1021 1022 ipu_dc_init(sc, DI_PORT); 1023 reg = IPU_READ4(sc, IPU_CONF); 1024 reg |= IPU_CONF_DMFC_EN | IPU_CONF_DC_EN | IPU_CONF_DP_EN; 1025 IPU_WRITE4(sc, IPU_CONF, reg); 1026 1027 ipu_config_timing(sc, DI_PORT); 1028 ipu_init_buffer(sc); 1029 ipu_di_enable(sc, DI_PORT); 1030 1031 /* Enable DMA channel */ 1032 off = (DMA_CHANNEL > 31) ? IPU_IDMAC_CH_EN_2 : IPU_IDMAC_CH_EN_1; 1033 reg = IPU_READ4(sc, off); 1034 reg |= (1 << (DMA_CHANNEL & 0x1f)); 1035 IPU_WRITE4(sc, off, reg); 1036 1037 ipu_dc_enable(sc); 1038 1039 sc->sc_fb_info.fb_name = device_get_nameunit(sc->sc_dev); 1040 sc->sc_fb_info.fb_vbase = (intptr_t)sc->sc_fb_base; 1041 sc->sc_fb_info.fb_pbase = sc->sc_fb_phys; 1042 sc->sc_fb_info.fb_size = sc->sc_fb_size; 1043 sc->sc_fb_info.fb_bpp = sc->sc_fb_info.fb_depth = MODE_BPP; 1044 sc->sc_fb_info.fb_stride = sc->sc_mode->hdisplay * MODE_BPP / 8; 1045 sc->sc_fb_info.fb_width = sc->sc_mode->hdisplay; 1046 sc->sc_fb_info.fb_height = sc->sc_mode->vdisplay; 1047 1048 device_t fbd = device_add_child(sc->sc_dev, "fbd", 1049 device_get_unit(sc->sc_dev)); 1050 if (fbd == NULL) { 1051 device_printf(sc->sc_dev, "Failed to add fbd child\n"); 1052 goto fail; 1053 } 1054 if (device_probe_and_attach(fbd) != 0) { 1055 device_printf(sc->sc_dev, "Failed to attach fbd device\n"); 1056 goto fail; 1057 } 1058 1059 return (0); 1060 fail: 1061 1062 return (err); 1063 } 1064 1065 static int 1066 ipu_mode_is_valid(const struct videomode *mode) 1067 { 1068 if ((mode->dot_clock < 13500) || (mode->dot_clock > 216000)) 1069 return (0); 1070 1071 return (1); 1072 } 1073 1074 static const struct videomode * 1075 ipu_pick_mode(struct edid_info *ei) 1076 { 1077 const struct videomode *videomode; 1078 const struct videomode *m; 1079 int n; 1080 1081 videomode = NULL; 1082 1083 /* 1084 * Pick a mode. 1085 */ 1086 if (ei->edid_preferred_mode != NULL) { 1087 if (ipu_mode_is_valid(ei->edid_preferred_mode)) 1088 videomode = ei->edid_preferred_mode; 1089 } 1090 1091 if (videomode == NULL) { 1092 m = ei->edid_modes; 1093 1094 sort_modes(ei->edid_modes, 1095 &ei->edid_preferred_mode, 1096 ei->edid_nmodes); 1097 for (n = 0; n < ei->edid_nmodes; n++) 1098 if (ipu_mode_is_valid(&m[n])) { 1099 videomode = &m[n]; 1100 break; 1101 } 1102 } 1103 1104 return videomode; 1105 } 1106 1107 static void 1108 ipu_hdmi_event(void *arg, device_t hdmi_dev) 1109 { 1110 struct ipu_softc *sc; 1111 uint8_t *edid; 1112 uint32_t edid_len; 1113 struct edid_info ei; 1114 const struct videomode *videomode; 1115 1116 sc = arg; 1117 1118 edid = NULL; 1119 edid_len = 0; 1120 if (CRTC_GET_EDID(hdmi_dev, &edid, &edid_len) != 0) { 1121 device_printf(sc->sc_dev, "failed to get EDID info from HDMI framer\n"); 1122 } 1123 1124 videomode = NULL; 1125 1126 if ( edid && (edid_parse(edid, &ei) == 0)) { 1127 if (bootverbose) 1128 edid_print(&ei); 1129 videomode = ipu_pick_mode(&ei); 1130 } else 1131 device_printf(sc->sc_dev, "failed to parse EDID\n"); 1132 1133 /* Use standard VGA as fallback */ 1134 if (videomode == NULL) 1135 videomode = pick_mode_by_ref(640, 480, 60); 1136 1137 if (videomode == NULL) { 1138 device_printf(sc->sc_dev, "failed to find usable videomode\n"); 1139 return; 1140 } 1141 1142 sc->sc_mode = videomode; 1143 1144 if (bootverbose) 1145 device_printf(sc->sc_dev, "detected videomode: %dx%d\n", 1146 videomode->hdisplay, videomode->vdisplay); 1147 1148 ipu_init(sc); 1149 1150 CRTC_SET_VIDEOMODE(hdmi_dev, sc->sc_mode); 1151 } 1152 1153 static int 1154 ipu_probe(device_t dev) 1155 { 1156 1157 if (have_ipu) 1158 return (ENXIO); 1159 1160 if (!ofw_bus_status_okay(dev)) 1161 return (ENXIO); 1162 1163 if (!ofw_bus_is_compatible(dev, "fsl,imx6q-ipu")) 1164 return (ENXIO); 1165 1166 device_set_desc(dev, "Freescale IPU"); 1167 1168 return (BUS_PROBE_DEFAULT); 1169 } 1170 1171 static int 1172 ipu_attach(device_t dev) 1173 { 1174 struct ipu_softc *sc; 1175 1176 if (have_ipu) 1177 return (ENXIO); 1178 1179 sc = device_get_softc(dev); 1180 sc->sc_dev = dev; 1181 1182 sc->sc_mem_rid = 0; 1183 sc->sc_mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, 1184 &sc->sc_mem_rid, RF_ACTIVE); 1185 if (!sc->sc_mem_res) { 1186 device_printf(dev, "cannot allocate memory window\n"); 1187 return (ENXIO); 1188 } 1189 1190 sc->sc_irq_rid = 0; 1191 sc->sc_irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, 1192 &sc->sc_irq_rid, RF_ACTIVE); 1193 if (!sc->sc_irq_res) { 1194 bus_release_resource(dev, SYS_RES_MEMORY, 1195 sc->sc_mem_rid, sc->sc_mem_res); 1196 device_printf(dev, "cannot allocate interrupt\n"); 1197 return (ENXIO); 1198 } 1199 1200 /* Enable IPU1 */ 1201 if (imx_ccm_pll_video_enable() != 0) { 1202 bus_release_resource(dev, SYS_RES_MEMORY, 1203 sc->sc_mem_rid, sc->sc_mem_res); 1204 bus_release_resource(dev, SYS_RES_IRQ, 1205 sc->sc_irq_rid, sc->sc_irq_res); 1206 device_printf(dev, "failed to set up video PLL\n"); 1207 return (ENXIO); 1208 } 1209 1210 imx_ccm_ipu_enable(1); 1211 1212 if (src_reset_ipu() != 0) { 1213 bus_release_resource(dev, SYS_RES_MEMORY, 1214 sc->sc_mem_rid, sc->sc_mem_res); 1215 bus_release_resource(dev, SYS_RES_IRQ, 1216 sc->sc_irq_rid, sc->sc_irq_res); 1217 device_printf(dev, "failed to reset IPU\n"); 1218 return (ENXIO); 1219 } 1220 1221 IPU_LOCK_INIT(sc); 1222 1223 sc->sc_hdmi_evh = EVENTHANDLER_REGISTER(hdmi_event, 1224 ipu_hdmi_event, sc, 0); 1225 1226 have_ipu = 1; 1227 1228 return (0); 1229 } 1230 1231 static int 1232 ipu_detach(device_t dev) 1233 { 1234 /* Do not let unload driver */ 1235 return (EBUSY); 1236 } 1237 1238 static struct fb_info * 1239 ipu_fb_getinfo(device_t dev) 1240 { 1241 struct ipu_softc *sc; 1242 1243 sc = device_get_softc(dev); 1244 1245 return (&sc->sc_fb_info); 1246 } 1247 1248 static device_method_t ipu_methods[] = { 1249 DEVMETHOD(device_probe, ipu_probe), 1250 DEVMETHOD(device_attach, ipu_attach), 1251 DEVMETHOD(device_detach, ipu_detach), 1252 1253 /* Framebuffer service methods */ 1254 DEVMETHOD(fb_getinfo, ipu_fb_getinfo), 1255 1256 DEVMETHOD_END 1257 }; 1258 1259 static driver_t ipu_driver = { 1260 "fb", 1261 ipu_methods, 1262 sizeof(struct ipu_softc), 1263 }; 1264 1265 DRIVER_MODULE(ipu, simplebus, ipu_driver, 0, 0); 1266 MODULE_VERSION(ipu, 1); 1267 MODULE_DEPEND(ipu, simplebus, 1, 1, 1); 1268