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