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 __FBSDID("$FreeBSD$"); 29 30 #include <sys/param.h> 31 #include <sys/systm.h> 32 #include <sys/kernel.h> 33 #include <sys/module.h> 34 #include <sys/clock.h> 35 #include <sys/time.h> 36 #include <sys/bus.h> 37 #include <sys/lock.h> 38 #include <sys/mutex.h> 39 #include <sys/resource.h> 40 #include <sys/rman.h> 41 #include <sys/sysctl.h> 42 #include <sys/fbio.h> 43 #include <sys/consio.h> 44 45 #include <machine/bus.h> 46 47 #include <dev/ofw/openfirm.h> 48 #include <dev/ofw/ofw_bus.h> 49 #include <dev/ofw/ofw_bus_subr.h> 50 51 #include <dev/fb/fbreg.h> 52 #include <dev/vt/vt.h> 53 54 #include <dev/videomode/videomode.h> 55 #include <dev/videomode/edidvar.h> 56 57 #include <arm/freescale/imx/imx6_src.h> 58 #include <arm/freescale/imx/imx_ccmvar.h> 59 60 #include "fb_if.h" 61 #include "hdmi_if.h" 62 63 #define EDID_DEBUG_not 64 65 static int have_ipu = 0; 66 67 #define LDB_CLOCK_RATE 280000000 68 69 #define MODE_HBP(mode) ((mode)->htotal - (mode)->hsync_end) 70 #define MODE_HFP(mode) ((mode)->hsync_start - (mode)->hdisplay) 71 #define MODE_HSW(mode) ((mode)->hsync_end - (mode)->hsync_start) 72 #define MODE_VBP(mode) ((mode)->vtotal - (mode)->vsync_end) 73 #define MODE_VFP(mode) ((mode)->vsync_start - (mode)->vdisplay) 74 #define MODE_VSW(mode) ((mode)->vsync_end - (mode)->vsync_start) 75 76 #define MODE_BPP 16 77 #define MODE_PIXEL_CLOCK_INVERT 1 78 79 #define M(nm,hr,vr,clk,hs,he,ht,vs,ve,vt,f) \ 80 { clk, hr, hs, he, ht, vr, vs, ve, vt, f, nm } 81 82 static struct videomode mode1024x768 = M("1024x768x60",1024,768,65000,1048,1184,1344,771,777,806,VID_NHSYNC|VID_PHSYNC); 83 84 #define DMA_CHANNEL 23 85 #define DC_CHAN5 5 86 #define DI_PORT 0 87 88 #define IPU_LOCK(_sc) mtx_lock(&(_sc)->sc_mtx) 89 #define IPU_UNLOCK(_sc) mtx_unlock(&(_sc)->sc_mtx) 90 #define IPU_LOCK_INIT(_sc) mtx_init(&(_sc)->sc_mtx, \ 91 device_get_nameunit(_sc->sc_dev), "ipu", MTX_DEF) 92 #define IPU_LOCK_DESTROY(_sc) mtx_destroy(&(_sc)->sc_mtx) 93 94 #define IPU_READ4(_sc, reg) bus_read_4((_sc)->sc_mem_res, (reg)) 95 #define IPU_WRITE4(_sc, reg, value) \ 96 bus_write_4((_sc)->sc_mem_res, (reg), (value)) 97 98 #define CPMEM_BASE 0x300000 99 #define DC_TEMPL_BASE 0x380000 100 101 /* Microcode */ 102 /* Word 1 */ 103 #define TEMPLATE_SYNC(v) ((v) << 0) 104 #define TEMPLATE_GLUELOGIC(v) ((v) << 4) 105 #define TEMPLATE_MAPPING(v) ((v) << 15) 106 #define TEMPLATE_WAVEFORM(v) ((v) << 11) 107 #define GLUELOGIC_KEEP_ASSERTED (1 << 3) 108 #define GLUELOGIC_KEEP_NEGATED (1 << 2) 109 /* Word 2 */ 110 #define TEMPLATE_OPCODE(v) ((v) << 4) 111 #define OPCODE_WROD 0x18 112 #define TEMPLATE_STOP (1 << 9) 113 114 #define IPU_CONF 0x200000 115 #define IPU_CONF_DMFC_EN (1 << 10) 116 #define IPU_CONF_DC_EN (1 << 9) 117 #define IPU_CONF_DI1_EN (1 << 7) 118 #define IPU_CONF_DI0_EN (1 << 6) 119 #define IPU_CONF_DP_EN (1 << 5) 120 #define IPU_DISP_GEN 0x2000C4 121 #define DISP_GEN_DI1_CNTR_RELEASE (1 << 25) 122 #define DISP_GEN_DI0_CNTR_RELEASE (1 << 24) 123 #define DISP_GEN_MCU_MAX_BURST_STOP (1 << 22) 124 #define DISP_GEN_MCU_T_SHIFT 18 125 #define IPU_MEM_RST 0x2000DC 126 #define IPU_MEM_RST_START (1 << 31) 127 #define IPU_MEM_RST_ALL 0x807FFFFF 128 #define IPU_CH_DB_MODE_SEL_0 0x200150 129 #define IPU_CH_DB_MODE_SEL_1 0x200154 130 #define IPU_CUR_BUF_0 0x20023C 131 #define IPU_CUR_BUF_1 0x200240 132 133 #define IPU_IDMAC_CH_EN_1 0x208004 134 #define IPU_IDMAC_CH_EN_2 0x208008 135 #define IPU_IDMAC_CH_PRI_1 0x208014 136 #define IPU_IDMAC_CH_PRI_2 0x208018 137 138 #define IPU_DI0_GENERAL 0x240000 139 #define DI_CLOCK_EXTERNAL (1 << 20) 140 #define DI_GENERAL_POL_CLK (1 << 17) 141 #define DI_GENERAL_POLARITY_3 (1 << 2) 142 #define DI_GENERAL_POLARITY_2 (1 << 1) 143 #define IPU_DI0_BS_CLKGEN0 0x240004 144 #define DI_BS_CLKGEN0(_int, _frac) (((_int) << 4) | (_frac)) 145 #define IPU_DI0_BS_CLKGEN1 0x240008 146 #define DI_BS_CLKGEN1_DOWN(_int, _frac) ((((_int) << 1) | (_frac)) << 16) 147 #define IPU_DI0_SW_GEN0_1 0x24000C 148 #define DI_RUN_VALUE_M1(v) ((v) << 19) 149 #define DI_RUN_RESOLUTION(v) ((v) << 16) 150 #define DI_OFFSET_VALUE(v) ((v) << 3) 151 #define IPU_DI0_SW_GEN1_1 0x240030 152 #define DI_CNT_POLARITY_GEN_EN(v) ((v) << 29) 153 #define DI_CNT_AUTO_RELOAD (1 << 28) 154 #define DI_CNT_CLR_SEL(v) ((v) << 25) 155 #define DI_CNT_DOWN(v) ((v) << 16) 156 #define DI_CNT_POLARITY_TRIGGER_SEL(v) ((v) << 12) 157 #define DI_CNT_POLARITY_CLR_SEL(v) ((v) << 9) 158 #define IPU_DI0_SYNC_AS_GEN 0x240054 159 #define SYNC_AS_GEN_VSYNC_SEL(v) ((v) << 13) 160 #define SYNC_AS_GEN_SYNC_START(v) ((v) << 0) 161 #define IPU_DI0_DW_GEN_0 0x240058 162 #define DW_GEN_DI_ACCESS_SIZE(v) ((v) << 24) 163 #define DW_GEN_DI_COMPONENT_SIZE(v) ((v) << 16) 164 #define DW_GEN_DI_SET_MASK 3 165 #define DW_GEN_DI_PIN_15_SET(v) ((v) << 8) 166 #define IPU_DI0_DW_SET3_0 0x240118 167 #define DW_SET_DATA_CNT_DOWN(v) ((v) << 16) 168 #define DW_SET_DATA_CNT_UP(v) ((v) << 0) 169 #define IPU_DI0_STP_REP 0x240148 170 #define IPU_DI0_POL 0x240164 171 #define DI_POL_DRDY_POLARITY_15 (1 << 4) 172 #define IPU_DI0_SCR_CONF 0x240170 173 174 #define IPU_DI1_GENERAL 0x248000 175 #define IPU_DI1_BS_CLKGEN0 0x248004 176 #define IPU_DI1_BS_CLKGEN1 0x248008 177 #define IPU_DI1_SW_GEN0_1 0x24800C 178 #define IPU_DI1_SW_GEN1_1 0x248030 179 #define IPU_DI1_SYNC_AS_GEN 0x248054 180 #define IPU_DI1_DW_GEN_0 0x248058 181 #define IPU_DI1_POL 0x248164 182 #define IPU_DI1_DW_SET3_0 0x248118 183 #define IPU_DI1_STP_REP 0x248148 184 #define IPU_DI1_SCR_CONF 0x248170 185 #define DMFC_RD_CHAN 0x260000 186 #define DMFC_WR_CHAN 0x260004 187 #define DMFC_WR_CHAN_BURST_SIZE_32 (0 << 6) 188 #define DMFC_WR_CHAN_BURST_SIZE_16 (1 << 6) 189 #define DMFC_WR_CHAN_BURST_SIZE_8 (2 << 6) 190 #define DMFC_WR_CHAN_BURST_SIZE_4 (3 << 6) 191 #define DMFC_WR_CHAN_BURST_SIZE_4 (3 << 6) 192 #define DMFC_WR_CHAN_FIFO_SIZE_128 (2 << 3) 193 #define DMFC_WR_CHAN_DEF 0x260008 194 #define DMFC_WR_CHAN_DEF_WM_CLR_2C(v) ((v) << 29) 195 #define DMFC_WR_CHAN_DEF_WM_CLR_1C(v) ((v) << 21) 196 #define DMFC_WR_CHAN_DEF_WM_CLR_2(v) ((v) << 13) 197 #define DMFC_WR_CHAN_DEF_WM_CLR_1(v) ((v) << 5) 198 #define DMFC_WR_CHAN_DEF_WM_SET_1(v) ((v) << 2) 199 #define DMFC_WR_CHAN_DEF_WM_EN_1 (1 << 1) 200 #define DMFC_DP_CHAN 0x26000C 201 #define DMFC_DP_CHAN_BURST_SIZE_8 2 202 #define DMFC_DP_CHAN_FIFO_SIZE_256 1 203 #define DMFC_DP_CHAN_FIFO_SIZE_128 2 204 #define DMFC_DP_CHAN_BURST_SIZE_5F(v) ((v) << 14) 205 #define DMFC_DP_CHAN_FIFO_SIZE_5F(v) ((v) << 11) 206 #define DMFC_DP_CHAN_ST_ADDR_SIZE_5F(v) ((v) << 8) 207 #define DMFC_DP_CHAN_BURST_SIZE_5B(v) ((v) << 6) 208 #define DMFC_DP_CHAN_FIFO_SIZE_5B(v) ((v) << 3) 209 #define DMFC_DP_CHAN_ST_ADDR_SIZE_5B(v) ((v) << 0) 210 #define DMFC_DP_CHAN_DEF 0x260010 211 #define DMFC_DP_CHAN_DEF_WM_CLR_6F(v) ((v) << 29) 212 #define DMFC_DP_CHAN_DEF_WM_CLR_6B(v) ((v) << 21) 213 #define DMFC_DP_CHAN_DEF_WM_CLR_5F(v) ((v) << 13) 214 #define DMFC_DP_CHAN_DEF_WM_SET_5F(v) ((v) << 10) 215 #define DMFC_DP_CHAN_DEF_WM_EN_5F (1 << 9) 216 #define DMFC_DP_CHAN_DEF_WM_CLR_5B(v) ((v) << 5) 217 #define DMFC_DP_CHAN_DEF_WM_SET_5B(v) ((v) << 2) 218 #define DMFC_DP_CHAN_DEF_WM_EN_5B (1 << 1) 219 #define DMFC_GENERAL_1 0x260014 220 #define DMFC_GENERAL_1_WAIT4EOT_5B (1 << 20) 221 #define DMFC_IC_CTRL 0x26001C 222 #define DMFC_IC_CTRL_DISABLED 0x2 223 224 #define DC_WRITE_CH_CONF_1 0x0025801C 225 #define WRITE_CH_CONF_PROG_CHAN_TYP_MASK (7 << 5) 226 #define WRITE_CH_CONF_PROG_CHAN_NORMAL (4 << 5) 227 #define DC_WRITE_CH_ADDR_1 0x00258020 228 #define DC_WRITE_CH_CONF_5 0x0025805C 229 #define WRITE_CH_CONF_PROG_DISP_ID(v) ((v) << 3) 230 #define WRITE_CH_CONF_PROG_DI_ID(v) ((v) << 2) 231 #define WRITE_CH_CONF_PROG_W_SIZE(v) (v) 232 #define DC_WRITE_CH_ADDR_5 0x00258060 233 #define DC_RL0_CH_5 0x00258064 234 #define DC_GEN 0x002580D4 235 #define DC_GEN_SYNC_PRIORITY (1 << 7) 236 #define DC_GEN_ASYNC (0 << 1) 237 #define DC_GEN_SYNC (2 << 1) 238 #define DC_DISP_CONF2(di) (0x002580E8 + (di) * 4) 239 #define DC_MAP_CONF_0 0x00258108 240 #define DC_MAP_CONF_15 0x00258144 241 #define DC_MAP_CONF_VAL(map) (DC_MAP_CONF_15 + ((map) / 2) * sizeof(uint32_t)) 242 #define MAP_CONF_VAL_MASK 0xffff 243 #define DC_MAP_CONF_PTR(ptr) (DC_MAP_CONF_0 + ((ptr) / 2) * sizeof(uint32_t)) 244 #define MAP_CONF_PTR_MASK 0x1f 245 246 #define DI_COUNTER_INT_HSYNC 1 247 #define DI_COUNTER_HSYNC 2 248 #define DI_COUNTER_VSYNC 3 249 #define DI_COUNTER_AD_0 4 250 #define DI_COUNTER_AD_1 5 251 252 #define DI_SYNC_NONE 0 253 #define DI_SYNC_CLK 1 254 #define DI_SYNC_COUNTER(c) ((c) + 1) 255 256 struct ipu_cpmem_word { 257 uint32_t data[5]; 258 uint32_t padding[3]; 259 }; 260 261 struct ipu_cpmem_ch_param { 262 struct ipu_cpmem_word word[2]; 263 }; 264 265 #define CH_PARAM_RESET(param) memset(param, 0, sizeof(*param)) 266 #define IPU_READ_CH_PARAM(_sc, ch, param) bus_read_region_4( \ 267 (_sc)->sc_mem_res, CPMEM_BASE + ch * (sizeof(*param)),\ 268 (uint32_t*)param, sizeof(*param) / 4) 269 #define IPU_WRITE_CH_PARAM(_sc, ch, param) bus_write_region_4( \ 270 (_sc)->sc_mem_res, CPMEM_BASE + ch * (sizeof(*param)),\ 271 (uint32_t*)param, sizeof(*param) / 4) 272 273 #define CH_PARAM_SET_FW(param, v) ipu_ch_param_set_value((param), \ 274 0, 125, 13, (v)) 275 #define CH_PARAM_SET_FH(param, v) ipu_ch_param_set_value((param), \ 276 0, 138, 12, (v)) 277 #define CH_PARAM_SET_SLY(param, v) ipu_ch_param_set_value((param), \ 278 1, 102, 14, (v)) 279 #define CH_PARAM_SET_EBA0(param, v) ipu_ch_param_set_value((param), \ 280 1, 0, 29, (v)) 281 #define CH_PARAM_SET_EBA1(param, v) ipu_ch_param_set_value((param), \ 282 1, 29, 29, (v)) 283 #define CH_PARAM_SET_BPP(param, v) ipu_ch_param_set_value((param), \ 284 0, 107, 3, (v)) 285 #define CH_PARAM_SET_PFS(param, v) ipu_ch_param_set_value((param), \ 286 1, 85, 4, (v)) 287 #define CH_PARAM_SET_NPB(param, v) ipu_ch_param_set_value((param), \ 288 1, 78, 7, (v)) 289 #define CH_PARAM_SET_UBO(param, v) ipu_ch_param_set_value((param), \ 290 0, 46, 22, (v)) 291 #define CH_PARAM_SET_VBO(param, v) ipu_ch_param_set_value((param), \ 292 0, 68, 22, (v)) 293 294 #define CH_PARAM_SET_RED_WIDTH(param, v) ipu_ch_param_set_value((param), \ 295 1, 116, 3, (v)) 296 #define CH_PARAM_SET_RED_OFFSET(param, v) ipu_ch_param_set_value((param), \ 297 1, 128, 5, (v)) 298 299 #define CH_PARAM_SET_GREEN_WIDTH(param, v) ipu_ch_param_set_value((param), \ 300 1, 119, 3, (v)) 301 #define CH_PARAM_SET_GREEN_OFFSET(param, v) ipu_ch_param_set_value((param), \ 302 1, 133, 5, (v)) 303 304 #define CH_PARAM_SET_BLUE_WIDTH(param, v) ipu_ch_param_set_value((param), \ 305 1, 122, 3, (v)) 306 #define CH_PARAM_SET_BLUE_OFFSET(param, v) ipu_ch_param_set_value((param), \ 307 1, 138, 5, (v)) 308 309 #define CH_PARAM_SET_ALPHA_WIDTH(param, v) ipu_ch_param_set_value((param), \ 310 1, 125, 3, (v)) 311 #define CH_PARAM_SET_ALPHA_OFFSET(param, v) ipu_ch_param_set_value((param), \ 312 1, 143, 5, (v)) 313 314 #define CH_PARAM_GET_FW(param) ipu_ch_param_get_value((param), \ 315 0, 125, 13) 316 #define CH_PARAM_GET_FH(param) ipu_ch_param_get_value((param), \ 317 0, 138, 12) 318 #define CH_PARAM_GET_SLY(param) ipu_ch_param_get_value((param), \ 319 1, 102, 14) 320 #define CH_PARAM_GET_EBA0(param) ipu_ch_param_get_value((param), \ 321 1, 0, 29) 322 #define CH_PARAM_GET_EBA1(param) ipu_ch_param_get_value((param), \ 323 1, 29, 29) 324 #define CH_PARAM_GET_BPP(param) ipu_ch_param_get_value((param), \ 325 0, 107, 3) 326 #define CH_PARAM_GET_PFS(param) ipu_ch_param_get_value((param), \ 327 1, 85, 4) 328 #define CH_PARAM_GET_NPB(param) ipu_ch_param_get_value((param), \ 329 1, 78, 7) 330 #define CH_PARAM_GET_UBO(param) ipu_ch_param_get_value((param), \ 331 0, 46, 22) 332 #define CH_PARAM_GET_VBO(param) ipu_ch_param_get_value((param), \ 333 0, 68, 22) 334 335 #define CH_PARAM_GET_RED_WIDTH(param) ipu_ch_param_get_value((param), \ 336 1, 116, 3) 337 #define CH_PARAM_GET_RED_OFFSET(param) ipu_ch_param_get_value((param), \ 338 1, 128, 5) 339 340 #define CH_PARAM_GET_GREEN_WIDTH(param) ipu_ch_param_get_value((param), \ 341 1, 119, 3) 342 #define CH_PARAM_GET_GREEN_OFFSET(param) ipu_ch_param_get_value((param), \ 343 1, 133, 5) 344 345 #define CH_PARAM_GET_BLUE_WIDTH(param) ipu_ch_param_get_value((param), \ 346 1, 122, 3) 347 #define CH_PARAM_GET_BLUE_OFFSET(param) ipu_ch_param_get_value((param), \ 348 1, 138, 5) 349 350 #define CH_PARAM_GET_ALPHA_WIDTH(param) ipu_ch_param_get_value((param), \ 351 1, 125, 3) 352 #define CH_PARAM_GET_ALPHA_OFFSET(param) ipu_ch_param_get_value((param), \ 353 1, 143, 5) 354 355 #define IPU_PIX_FORMAT_BPP_32 0 356 #define IPU_PIX_FORMAT_BPP_24 1 357 #define IPU_PIX_FORMAT_BPP_18 2 358 #define IPU_PIX_FORMAT_BPP_16 3 359 #define IPU_PIX_FORMAT_BPP_12 4 360 #define IPU_PIX_FORMAT_BPP_8 5 361 #define IPU_PIX_FORMAT_BPP_ 362 363 #define IPU_PIX_FORMAT_RGB 7 364 365 enum dc_event_t { 366 DC_EVENT_NF = 0, 367 DC_EVENT_NL, 368 DC_EVENT_EOF, 369 DC_EVENT_NFIELD, 370 DC_EVENT_EOL, 371 DC_EVENT_EOFIELD, 372 DC_EVENT_NEW_ADDR, 373 DC_EVENT_NEW_CHAN, 374 DC_EVENT_NEW_DATA 375 }; 376 377 struct ipu_softc { 378 device_t sc_dev; 379 struct resource *sc_mem_res; 380 int sc_mem_rid; 381 struct resource *sc_irq_res; 382 int sc_irq_rid; 383 void *sc_intr_hl; 384 struct mtx sc_mtx; 385 struct fb_info sc_fb_info; 386 struct videomode *sc_mode; 387 388 /* Framebuffer */ 389 bus_dma_tag_t sc_dma_tag; 390 bus_dmamap_t sc_dma_map; 391 size_t sc_fb_size; 392 bus_addr_t sc_fb_phys; 393 uint8_t *sc_fb_base; 394 395 /* HDMI */ 396 eventhandler_tag sc_hdmi_evh; 397 }; 398 399 static void 400 ipu_dmamap_cb(void *arg, bus_dma_segment_t *segs, int nseg, int err) 401 { 402 bus_addr_t *addr; 403 404 if (err) 405 return; 406 407 addr = (bus_addr_t*)arg; 408 *addr = segs[0].ds_addr; 409 } 410 411 static void 412 ipu_ch_param_set_value(struct ipu_cpmem_ch_param *param, 413 int word, unsigned int offset, int len, uint32_t value) 414 { 415 uint32_t datapos, bitpos, mask; 416 uint32_t data, data2; 417 418 KASSERT((len <= 32), ("%s: field len is more than 32", __func__)); 419 420 datapos = offset / 32; 421 bitpos = offset % 32; 422 423 mask = (1 << len) - 1; 424 data = param->word[word].data[datapos]; 425 data &= ~(mask << bitpos); 426 data |= (value << bitpos); 427 param->word[word].data[datapos] = data; 428 429 if ((bitpos + len) > 32) { 430 len = bitpos + len - 32; 431 mask = (1UL << len) - 1; 432 data2 = param->word[word].data[datapos + 1]; 433 data2 &= mask; 434 data2 |= (value >> (32 - bitpos)); 435 param->word[word].data[datapos + 1] = data2; 436 } 437 } 438 439 #ifdef DEBUG 440 static uint32_t 441 ipu_ch_param_get_value(struct ipu_cpmem_ch_param *param, 442 int word, unsigned int offset, int len) 443 { 444 uint32_t datapos, bitpos, mask; 445 uint32_t data, data2; 446 447 KASSERT((len <= 32), ("%s: field len is more than 32", __func__)); 448 449 datapos = offset / 32; 450 bitpos = offset % 32; 451 mask = (1UL << len) - 1; 452 data = param->word[word].data[datapos]; 453 data = data >> bitpos; 454 data &= mask; 455 if ((bitpos + len) > 32) { 456 len = bitpos + len - 32; 457 mask = (1UL << len) - 1; 458 data2 = param->word[word].data[datapos + 1]; 459 data2 &= mask; 460 data |= (data2 << (32 - bitpos)); 461 } 462 463 return (data); 464 } 465 466 static void 467 ipu_print_channel(struct ipu_cpmem_ch_param *param) 468 { 469 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}; 470 int offset1[] = {0, 29, 58, 78, 85, 89, 90, 93, 95, 102, 116, 119, 122, 125, 128, 133, 138, 143, 148, 149, 150, -1}; 471 printf("WORD0: %08x %08x %08x %08x %08x\n", 472 param->word[0].data[0], param->word[0].data[1], 473 param->word[0].data[2], param->word[0].data[3], 474 param->word[0].data[4]); 475 printf("WORD1: %08x %08x %08x %08x %08x\n", 476 param->word[1].data[0], param->word[1].data[1], 477 param->word[1].data[2], param->word[1].data[3], 478 param->word[1].data[4]); 479 480 for (int i = 0; offset0[i + 1] != -1; i++) { 481 int len = offset0[i + 1] - offset0[i]; 482 printf("W0[%d:%d] = %d\n", offset0[i], 483 offset0[i] + len - 1, 484 ipu_ch_param_get_value(param, 0, offset0[i], len) 485 ); 486 } 487 488 for (int i = 0; offset1[i + 1] != -1; i++) { 489 int len = offset1[i + 1] - offset1[i]; 490 printf("W1[%d:%d] = %d\n", offset1[i], 491 offset1[i] + len - 1, 492 ipu_ch_param_get_value(param, 1, offset1[i], len) 493 ); 494 } 495 496 printf("FW: %d\n", CH_PARAM_GET_FW(param)); 497 printf("FH: %d\n", CH_PARAM_GET_FH(param)); 498 printf("SLY: %d\n", CH_PARAM_GET_SLY(param)); 499 printf("EBA0: 0x%08x\n", CH_PARAM_GET_EBA0(param)); 500 printf("EBA1: 0x%08x\n", CH_PARAM_GET_EBA1(param)); 501 printf("BPP: %d\n", CH_PARAM_GET_BPP(param)); 502 printf("PFS: %d\n", CH_PARAM_GET_PFS(param)); 503 printf("NPB: %d\n", CH_PARAM_GET_NPB(param)); 504 printf("UBO: %d\n", CH_PARAM_GET_UBO(param)); 505 printf("VBO: %d\n", CH_PARAM_GET_VBO(param)); 506 printf("RED: %d bits @%d\n", CH_PARAM_GET_RED_WIDTH(param) + 1, 507 CH_PARAM_GET_RED_OFFSET(param)); 508 printf("GREEN: %d bits @%d\n", CH_PARAM_GET_GREEN_WIDTH(param) + 1, 509 CH_PARAM_GET_GREEN_OFFSET(param)); 510 printf("BLUE: %d bits @%d\n", CH_PARAM_GET_BLUE_WIDTH(param) + 1, 511 CH_PARAM_GET_BLUE_OFFSET(param)); 512 printf("ALPHA: %d bits @%d\n", CH_PARAM_GET_ALPHA_WIDTH(param) + 1, 513 CH_PARAM_GET_ALPHA_OFFSET(param)); 514 } 515 #endif 516 517 static void 518 ipu_di_enable(struct ipu_softc *sc, int di) 519 { 520 uint32_t flag, reg; 521 522 flag = di ? DISP_GEN_DI1_CNTR_RELEASE : DISP_GEN_DI0_CNTR_RELEASE; 523 reg = IPU_READ4(sc, IPU_DISP_GEN); 524 reg |= flag; 525 IPU_WRITE4(sc, IPU_DISP_GEN, reg); 526 } 527 528 static void 529 ipu_config_wave_gen_0(struct ipu_softc *sc, int di, 530 int wave_gen, int run_value, int run_res, 531 int offset_value, int offset_res) 532 { 533 uint32_t addr, reg; 534 535 addr = (di ? IPU_DI1_SW_GEN0_1 : IPU_DI0_SW_GEN0_1) 536 + (wave_gen - 1) * sizeof(uint32_t); 537 reg = DI_RUN_VALUE_M1(run_value) | 538 DI_RUN_RESOLUTION(run_res) | 539 DI_OFFSET_VALUE(offset_value) | offset_res; 540 IPU_WRITE4(sc, addr, reg); 541 } 542 543 static void 544 ipu_config_wave_gen_1(struct ipu_softc *sc, int di, int wave_gen, 545 int repeat_count, int cnt_clr_src, 546 int cnt_polarity_gen_en, 547 int cnt_polarity_clr_src, 548 int cnt_polarity_trigger_src, 549 int cnt_up, int cnt_down) 550 { 551 uint32_t addr, reg; 552 553 addr = (di ? IPU_DI1_SW_GEN1_1 : IPU_DI0_SW_GEN1_1) 554 + (wave_gen - 1) * sizeof(uint32_t); 555 reg = DI_CNT_POLARITY_GEN_EN(cnt_polarity_gen_en) | 556 DI_CNT_CLR_SEL(cnt_clr_src) | 557 DI_CNT_POLARITY_TRIGGER_SEL(cnt_polarity_trigger_src) | 558 DI_CNT_POLARITY_CLR_SEL(cnt_polarity_clr_src); 559 reg |= DI_CNT_DOWN(cnt_down) | cnt_up; 560 if (repeat_count == 0) 561 reg |= DI_CNT_AUTO_RELOAD; 562 IPU_WRITE4(sc, addr, reg); 563 564 addr = (di ? IPU_DI1_STP_REP : IPU_DI0_STP_REP) 565 + (wave_gen - 1) / 2 * sizeof(uint32_t); 566 reg = IPU_READ4(sc, addr); 567 if (wave_gen % 2) { 568 reg &= ~(0xffff); 569 reg |= repeat_count; 570 } 571 else { 572 reg &= ~(0xffff << 16); 573 reg |= (repeat_count << 16); 574 } 575 IPU_WRITE4(sc, addr, reg); 576 } 577 578 static void 579 ipu_reset_wave_gen(struct ipu_softc *sc, int di, 580 int wave_gen) 581 { 582 uint32_t addr, reg; 583 584 addr = (di ? IPU_DI1_SW_GEN0_1 : IPU_DI0_SW_GEN0_1) 585 + (wave_gen - 1) * sizeof(uint32_t); 586 IPU_WRITE4(sc, addr, 0); 587 588 addr = (di ? IPU_DI1_SW_GEN1_1 : IPU_DI0_SW_GEN1_1) 589 + (wave_gen - 1) * sizeof(uint32_t); 590 IPU_WRITE4(sc, addr, 0); 591 592 addr = (di ? IPU_DI1_STP_REP : IPU_DI0_STP_REP) 593 + (wave_gen - 1) / 2 * sizeof(uint32_t); 594 reg = IPU_READ4(sc, addr); 595 if (wave_gen % 2) 596 reg &= ~(0xffff); 597 else 598 reg &= ~(0xffff << 16); 599 IPU_WRITE4(sc, addr, reg); 600 } 601 602 static void 603 ipu_init_microcode_template(struct ipu_softc *sc, int di, int map) 604 { 605 uint32_t addr; 606 uint32_t w1, w2; 607 int i, word; 608 int glue; 609 610 word = di ? 2 : 5; 611 612 for (i = 0; i < 3; i++) { 613 if (i == 0) 614 glue = GLUELOGIC_KEEP_ASSERTED; 615 else if (i == 1) 616 glue = GLUELOGIC_KEEP_NEGATED; 617 else if (i == 2) 618 glue = 0; 619 620 w1 = TEMPLATE_SYNC(5) | 621 TEMPLATE_GLUELOGIC(glue) | 622 TEMPLATE_WAVEFORM(1) | /* wave unit 0 */ 623 TEMPLATE_MAPPING(map + 1); 624 /* operand is zero */ 625 626 /* Write data to DI and Hold data in register */ 627 w2 = TEMPLATE_OPCODE(OPCODE_WROD) | 628 TEMPLATE_STOP; 629 630 addr = DC_TEMPL_BASE + (word + i) * 2 * sizeof(uint32_t); 631 IPU_WRITE4(sc, addr, w1); 632 IPU_WRITE4(sc, addr + sizeof(uint32_t), w2); 633 } 634 } 635 636 static void 637 ipu_config_timing(struct ipu_softc *sc, int di) 638 { 639 int div; 640 uint32_t di_scr_conf; 641 uint32_t gen_offset, gen; 642 uint32_t as_gen_offset, as_gen; 643 uint32_t dw_gen_offset, dw_gen; 644 uint32_t dw_set_offset, dw_set; 645 uint32_t bs_clkgen_offset; 646 int map; 647 648 /* TODO: check mode restrictions / fixup */ 649 /* TODO: enable timers, get divisors */ 650 div = 1; 651 map = 0; 652 653 bs_clkgen_offset = di ? IPU_DI1_BS_CLKGEN0 : IPU_DI0_BS_CLKGEN0; 654 IPU_WRITE4(sc, bs_clkgen_offset, DI_BS_CLKGEN0(div, 0)); 655 /* half of the divider */ 656 IPU_WRITE4(sc, bs_clkgen_offset + 4, DI_BS_CLKGEN1_DOWN(div / 2, div % 2)); 657 658 /* 659 * TODO: Configure LLDB clock by changing following fields 660 * in CCM fields: 661 * CS2CDR_LDB_DI0_CLK_SEL 662 * CSCMR2_LDB_DI0_IPU_DIV 663 * CBCDR_MMDC_CH1_AXI_PODF 664 */ 665 666 /* Setup wave generator */ 667 dw_gen_offset = di ? IPU_DI1_DW_GEN_0 : IPU_DI0_DW_GEN_0; 668 dw_gen = DW_GEN_DI_ACCESS_SIZE(div - 1) | DW_GEN_DI_COMPONENT_SIZE(div - 1); 669 dw_gen &= ~DW_GEN_DI_PIN_15_SET(DW_GEN_DI_SET_MASK); 670 dw_gen |= DW_GEN_DI_PIN_15_SET(3); /* set 3*/ 671 IPU_WRITE4(sc, dw_gen_offset, dw_gen); 672 673 dw_set_offset = di ? IPU_DI1_DW_SET3_0 : IPU_DI0_DW_SET3_0; 674 dw_set = DW_SET_DATA_CNT_DOWN(div * 2) | DW_SET_DATA_CNT_UP(0); 675 IPU_WRITE4(sc, dw_set_offset, dw_set); 676 677 /* DI_COUNTER_INT_HSYNC */ 678 ipu_config_wave_gen_0(sc, di, DI_COUNTER_INT_HSYNC, 679 sc->sc_mode->htotal - 1, DI_SYNC_CLK, 0, DI_SYNC_NONE); 680 ipu_config_wave_gen_1(sc, di, DI_COUNTER_INT_HSYNC, 681 0, DI_SYNC_NONE, 0, DI_SYNC_NONE, DI_SYNC_NONE, 0, 0); 682 683 /* DI_COUNTER_HSYNC */ 684 ipu_config_wave_gen_0(sc, di, DI_COUNTER_HSYNC, 685 sc->sc_mode->htotal - 1, DI_SYNC_CLK, 0, DI_SYNC_CLK); 686 ipu_config_wave_gen_1(sc, di, DI_COUNTER_HSYNC, 687 0, DI_SYNC_NONE, 1, DI_SYNC_NONE, DI_SYNC_CLK, 688 0, MODE_HSW(sc->sc_mode) * 2); 689 690 /* DI_COUNTER_VSYNC */ 691 ipu_config_wave_gen_0(sc, di, DI_COUNTER_VSYNC, 692 sc->sc_mode->vtotal - 1, DI_SYNC_COUNTER(DI_COUNTER_INT_HSYNC), 693 0, DI_SYNC_NONE); 694 ipu_config_wave_gen_1(sc, di, DI_COUNTER_VSYNC, 695 0, DI_SYNC_NONE, 1, DI_SYNC_NONE, 696 DI_SYNC_COUNTER(DI_COUNTER_INT_HSYNC), 697 0, MODE_VSW(sc->sc_mode) * 2); 698 699 di_scr_conf = di ? IPU_DI1_SCR_CONF : IPU_DI0_SCR_CONF; 700 IPU_WRITE4(sc, di_scr_conf, sc->sc_mode->vtotal - 1); 701 702 /* TODO: update DI_SCR_CONF */ 703 704 /* Active Data 0 */ 705 ipu_config_wave_gen_0(sc, di, DI_COUNTER_AD_0, 706 0, DI_SYNC_COUNTER(DI_COUNTER_HSYNC), 707 MODE_VSW(sc->sc_mode) + MODE_VFP(sc->sc_mode), DI_SYNC_COUNTER(DI_COUNTER_HSYNC)); 708 ipu_config_wave_gen_1(sc, di, DI_COUNTER_AD_0, 709 sc->sc_mode->vdisplay, DI_SYNC_COUNTER(DI_COUNTER_VSYNC), 710 0, DI_SYNC_NONE, DI_SYNC_NONE, 0, 0); 711 712 ipu_config_wave_gen_0(sc, di, DI_COUNTER_AD_1, 713 0, DI_SYNC_CLK, MODE_HSW(sc->sc_mode) + MODE_HFP(sc->sc_mode), DI_SYNC_CLK); 714 ipu_config_wave_gen_1(sc, di, DI_COUNTER_AD_1, 715 sc->sc_mode->hdisplay, DI_SYNC_COUNTER(DI_COUNTER_AD_0), 716 0, DI_SYNC_NONE, DI_SYNC_NONE, 0, 0); 717 718 ipu_reset_wave_gen(sc, di, 6); 719 ipu_reset_wave_gen(sc, di, 7); 720 ipu_reset_wave_gen(sc, di, 8); 721 ipu_reset_wave_gen(sc, di, 9); 722 723 ipu_init_microcode_template(sc, di, map); 724 725 gen_offset = di ? IPU_DI1_GENERAL : IPU_DI0_GENERAL; 726 gen = IPU_READ4(sc, gen_offset); 727 728 if (sc->sc_mode->flags & VID_NHSYNC) 729 gen &= ~DI_GENERAL_POLARITY_2; 730 else /* active high */ 731 gen |= DI_GENERAL_POLARITY_2; 732 733 if (sc->sc_mode->flags & VID_NVSYNC) 734 gen &= ~DI_GENERAL_POLARITY_3; 735 else /* active high */ 736 gen |= DI_GENERAL_POLARITY_3; 737 738 if (MODE_PIXEL_CLOCK_INVERT) 739 gen &= ~DI_GENERAL_POL_CLK; 740 else 741 gen |= DI_GENERAL_POL_CLK; 742 743 /* Use LDB clock to drive pixel clock */ 744 gen |= DI_CLOCK_EXTERNAL; 745 746 IPU_WRITE4(sc, gen_offset, gen); 747 748 as_gen_offset = di ? IPU_DI1_SYNC_AS_GEN : IPU_DI0_SYNC_AS_GEN; 749 as_gen = SYNC_AS_GEN_VSYNC_SEL(DI_COUNTER_VSYNC - 1) | 750 SYNC_AS_GEN_SYNC_START(2); 751 IPU_WRITE4(sc, as_gen_offset, as_gen); 752 753 IPU_WRITE4(sc, (di ? IPU_DI1_POL : IPU_DI0_POL), DI_POL_DRDY_POLARITY_15); 754 755 IPU_WRITE4(sc, DC_DISP_CONF2(di), sc->sc_mode->hdisplay); 756 } 757 758 static void 759 ipu_dc_enable(struct ipu_softc *sc) 760 { 761 uint32_t conf; 762 763 /* channel 1 uses DI1 */ 764 IPU_WRITE4(sc, DC_WRITE_CH_CONF_1, WRITE_CH_CONF_PROG_DI_ID(1)); 765 766 conf = IPU_READ4(sc, DC_WRITE_CH_CONF_5); 767 conf &= ~WRITE_CH_CONF_PROG_CHAN_TYP_MASK; 768 conf |= WRITE_CH_CONF_PROG_CHAN_NORMAL; 769 IPU_WRITE4(sc, DC_WRITE_CH_CONF_5, conf); 770 771 /* TODO: enable clock */ 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 void 1066 ipu_hdmi_event(void *arg, device_t hdmi_dev) 1067 { 1068 struct ipu_softc *sc; 1069 uint8_t *edid; 1070 uint32_t edid_len; 1071 #ifdef EDID_DEBUG 1072 struct edid_info ei; 1073 #endif 1074 const struct videomode *videomode; 1075 1076 sc = arg; 1077 1078 edid = NULL; 1079 edid_len = 0; 1080 if (HDMI_GET_EDID(hdmi_dev, &edid, &edid_len) != 0) { 1081 device_printf(sc->sc_dev, "failed to get EDID info from HDMI framer\n"); 1082 } 1083 1084 videomode = NULL; 1085 1086 #ifdef EDID_DEBUG 1087 if ( edid && (edid_parse(edid, &ei) == 0)) { 1088 edid_print(&ei); 1089 } else 1090 device_printf(sc->sc_dev, "failed to parse EDID\n"); 1091 #endif 1092 1093 sc->sc_mode = &mode1024x768; 1094 ipu_init(sc); 1095 1096 HDMI_SET_VIDEOMODE(hdmi_dev, sc->sc_mode); 1097 } 1098 1099 static int 1100 ipu_probe(device_t dev) 1101 { 1102 1103 if (have_ipu) 1104 return (ENXIO); 1105 1106 if (!ofw_bus_status_okay(dev)) 1107 return (ENXIO); 1108 1109 if (!ofw_bus_is_compatible(dev, "fsl,imx6q-ipu")) 1110 return (ENXIO); 1111 1112 device_set_desc(dev, "Freescale IPU"); 1113 1114 return (BUS_PROBE_DEFAULT); 1115 } 1116 1117 static int 1118 ipu_attach(device_t dev) 1119 { 1120 struct ipu_softc *sc; 1121 1122 if (have_ipu) 1123 return (ENXIO); 1124 1125 sc = device_get_softc(dev); 1126 sc->sc_dev = dev; 1127 1128 sc->sc_mem_rid = 0; 1129 sc->sc_mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, 1130 &sc->sc_mem_rid, RF_ACTIVE); 1131 if (!sc->sc_mem_res) { 1132 device_printf(dev, "cannot allocate memory window\n"); 1133 return (ENXIO); 1134 } 1135 1136 sc->sc_irq_rid = 0; 1137 sc->sc_irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, 1138 &sc->sc_irq_rid, RF_ACTIVE); 1139 if (!sc->sc_irq_res) { 1140 bus_release_resource(dev, SYS_RES_MEMORY, 1141 sc->sc_mem_rid, sc->sc_mem_res); 1142 device_printf(dev, "cannot allocate interrupt\n"); 1143 return (ENXIO); 1144 } 1145 1146 /* Enable IPU1 */ 1147 imx_ccm_ipu_enable(1); 1148 1149 if (src_reset_ipu() != 0) { 1150 device_printf(dev, "failed to reset IPU\n"); 1151 return (ENXIO); 1152 } 1153 1154 IPU_LOCK_INIT(sc); 1155 1156 sc->sc_hdmi_evh = EVENTHANDLER_REGISTER(hdmi_event, 1157 ipu_hdmi_event, sc, 0); 1158 1159 have_ipu = 1; 1160 1161 return (0); 1162 } 1163 1164 static int 1165 ipu_detach(device_t dev) 1166 { 1167 /* Do not let unload driver */ 1168 return (EBUSY); 1169 } 1170 1171 static struct fb_info * 1172 ipu_fb_getinfo(device_t dev) 1173 { 1174 struct ipu_softc *sc; 1175 1176 sc = device_get_softc(dev); 1177 1178 return (&sc->sc_fb_info); 1179 } 1180 1181 static device_method_t ipu_methods[] = { 1182 DEVMETHOD(device_probe, ipu_probe), 1183 DEVMETHOD(device_attach, ipu_attach), 1184 DEVMETHOD(device_detach, ipu_detach), 1185 1186 /* Framebuffer service methods */ 1187 DEVMETHOD(fb_getinfo, ipu_fb_getinfo), 1188 1189 DEVMETHOD_END 1190 }; 1191 1192 static driver_t ipu_driver = { 1193 "fb", 1194 ipu_methods, 1195 sizeof(struct ipu_softc), 1196 }; 1197 1198 static devclass_t ipu_devclass; 1199 1200 DRIVER_MODULE(ipu, simplebus, ipu_driver, ipu_devclass, 0, 0); 1201 MODULE_VERSION(ipu, 1); 1202 MODULE_DEPEND(ipu, simplebus, 1, 1, 1); 1203