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