1 1.49 andvar /* $NetBSD: tx3912video.c,v 1.49 2025/02/26 04:49:46 andvar Exp $ */ 2 1.1 uch 3 1.11 uch /*- 4 1.26 uch * Copyright (c) 1999-2002 The NetBSD Foundation, Inc. 5 1.18 uch * All rights reserved. 6 1.18 uch * 7 1.18 uch * This code is derived from software contributed to The NetBSD Foundation 8 1.18 uch * by UCHIYAMA Yasushi. 9 1.1 uch * 10 1.1 uch * Redistribution and use in source and binary forms, with or without 11 1.1 uch * modification, are permitted provided that the following conditions 12 1.1 uch * are met: 13 1.1 uch * 1. Redistributions of source code must retain the above copyright 14 1.1 uch * notice, this list of conditions and the following disclaimer. 15 1.10 uch * 2. Redistributions in binary form must reproduce the above copyright 16 1.10 uch * notice, this list of conditions and the following disclaimer in the 17 1.10 uch * documentation and/or other materials provided with the distribution. 18 1.1 uch * 19 1.18 uch * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20 1.18 uch * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21 1.18 uch * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 1.18 uch * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23 1.18 uch * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 1.18 uch * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 1.18 uch * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 1.18 uch * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 1.18 uch * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 1.18 uch * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 1.18 uch * POSSIBILITY OF SUCH DAMAGE. 30 1.1 uch */ 31 1.34 lukem 32 1.34 lukem #include <sys/cdefs.h> 33 1.49 andvar __KERNEL_RCSID(0, "$NetBSD: tx3912video.c,v 1.49 2025/02/26 04:49:46 andvar Exp $"); 34 1.18 uch 35 1.15 uch #define TX3912VIDEO_DEBUG 36 1.10 uch 37 1.8 uch #include "hpcfb.h" 38 1.26 uch #include "bivideo.h" 39 1.1 uch 40 1.1 uch #include <sys/param.h> 41 1.1 uch #include <sys/systm.h> 42 1.44 skrll #include <sys/buf.h> 43 1.1 uch #include <sys/device.h> 44 1.1 uch #include <sys/extent.h> 45 1.11 uch #include <sys/ioctl.h> 46 1.17 mrg 47 1.17 mrg #include <uvm/uvm_extern.h> 48 1.11 uch 49 1.19 uch #include <dev/cons.h> /* consdev */ 50 1.19 uch 51 1.1 uch #include <machine/bus.h> 52 1.10 uch #include <machine/bootinfo.h> 53 1.18 uch #include <machine/config_hook.h> 54 1.1 uch 55 1.45 matt #include <mips/locore.h> 56 1.45 matt 57 1.1 uch #include <hpcmips/tx/tx39var.h> 58 1.1 uch #include <hpcmips/tx/tx3912videovar.h> 59 1.1 uch #include <hpcmips/tx/tx3912videoreg.h> 60 1.1 uch 61 1.12 uch /* CLUT */ 62 1.12 uch #include <dev/wscons/wsdisplayvar.h> 63 1.12 uch #include <dev/rasops/rasops.h> 64 1.22 uch #include <dev/hpc/video_subr.h> 65 1.12 uch 66 1.9 sato #include <dev/wscons/wsconsio.h> 67 1.22 uch #include <dev/hpc/hpcfbvar.h> 68 1.22 uch #include <dev/hpc/hpcfbio.h> 69 1.26 uch #if NBIVIDEO > 0 70 1.26 uch #include <dev/hpc/bivideovar.h> 71 1.26 uch #endif 72 1.2 uch 73 1.18 uch #ifdef TX3912VIDEO_DEBUG 74 1.18 uch int tx3912video_debug = 1; 75 1.18 uch #define DPRINTF(arg) if (tx3912video_debug) printf arg; 76 1.18 uch #define DPRINTFN(n, arg) if (tx3912video_debug > (n)) printf arg; 77 1.18 uch #else 78 1.18 uch #define DPRINTF(arg) 79 1.18 uch #define DPRINTFN(n, arg) 80 1.18 uch #endif 81 1.18 uch 82 1.1 uch struct tx3912video_softc { 83 1.42 chs device_t sc_dev; 84 1.18 uch void *sc_powerhook; /* power management hook */ 85 1.19 uch int sc_console; 86 1.11 uch struct hpcfb_fbconf sc_fbconf; 87 1.11 uch struct hpcfb_dspconf sc_dspconf; 88 1.15 uch struct video_chip *sc_chip; 89 1.1 uch }; 90 1.1 uch 91 1.15 uch /* TX3912 built-in video chip itself */ 92 1.15 uch static struct video_chip tx3912video_chip; 93 1.15 uch 94 1.18 uch int tx3912video_power(void *, int, long, void *); 95 1.18 uch void tx3912video_framebuffer_init(struct video_chip *); 96 1.18 uch int tx3912video_framebuffer_alloc(struct video_chip *, paddr_t, paddr_t *); 97 1.18 uch void tx3912video_reset(struct video_chip *); 98 1.18 uch void tx3912video_resolution_init(struct video_chip *); 99 1.42 chs int tx3912video_match(device_t, cfdata_t, void *); 100 1.42 chs void tx3912video_attach(device_t, device_t, void *); 101 1.18 uch int tx3912video_print(void *, const char *); 102 1.18 uch 103 1.18 uch void tx3912video_hpcfbinit(struct tx3912video_softc *); 104 1.38 christos int tx3912video_ioctl(void *, u_long, void *, int, struct lwp *); 105 1.18 uch paddr_t tx3912video_mmap(void *, off_t, int); 106 1.18 uch 107 1.18 uch void tx3912video_clut_init(struct tx3912video_softc *); 108 1.18 uch void tx3912video_clut_install(void *, struct rasops_info *); 109 1.23 uch void tx3912video_clut_get(struct tx3912video_softc *, u_int32_t *, int, 110 1.23 uch int); 111 1.18 uch 112 1.18 uch static int __get_color8(int); 113 1.18 uch static int __get_color4(int); 114 1.12 uch 115 1.42 chs CFATTACH_DECL_NEW(tx3912video, sizeof(struct tx3912video_softc), 116 1.33 thorpej tx3912video_match, tx3912video_attach, NULL, NULL); 117 1.1 uch 118 1.11 uch struct hpcfb_accessops tx3912video_ha = { 119 1.12 uch tx3912video_ioctl, tx3912video_mmap, 0, 0, 0, 0, 120 1.12 uch tx3912video_clut_install 121 1.11 uch }; 122 1.11 uch 123 1.1 uch int 124 1.42 chs tx3912video_match(device_t parent, cfdata_t cf, void *aux) 125 1.1 uch { 126 1.23 uch return (ATTACH_NORMAL); 127 1.1 uch } 128 1.1 uch 129 1.1 uch void 130 1.42 chs tx3912video_attach(device_t parent, device_t self, void *aux) 131 1.1 uch { 132 1.42 chs struct tx3912video_softc *sc = device_private(self); 133 1.15 uch struct video_chip *chip; 134 1.30 yamt static const char *const depth_print[] = { 135 1.10 uch [TX3912_VIDEOCTRL1_BITSEL_MONOCHROME] = "monochrome", 136 1.10 uch [TX3912_VIDEOCTRL1_BITSEL_2BITGREYSCALE] = "2bit greyscale", 137 1.10 uch [TX3912_VIDEOCTRL1_BITSEL_4BITGREYSCALE] = "4bit greyscale", 138 1.10 uch [TX3912_VIDEOCTRL1_BITSEL_8BITCOLOR] = "8bit color" 139 1.10 uch }; 140 1.11 uch struct hpcfb_attach_args ha; 141 1.12 uch tx_chipset_tag_t tc; 142 1.12 uch txreg_t val; 143 1.19 uch int console; 144 1.10 uch 145 1.42 chs sc->sc_dev = self; 146 1.19 uch sc->sc_console = console = cn_tab ? 0 : 1; 147 1.10 uch sc->sc_chip = chip = &tx3912video_chip; 148 1.10 uch 149 1.10 uch /* print video module information */ 150 1.10 uch printf(": %s, frame buffer 0x%08x-0x%08x\n", 151 1.23 uch depth_print[(ffs(chip->vc_fbdepth) - 1) & 0x3], 152 1.23 uch (unsigned)chip->vc_fbpaddr, 153 1.23 uch (unsigned)(chip->vc_fbpaddr + chip->vc_fbsize)); 154 1.5 uch 155 1.12 uch /* don't inverse VDAT[3:0] signal */ 156 1.15 uch tc = chip->vc_v; 157 1.12 uch val = tx_conf_read(tc, TX3912_VIDEOCTRL1_REG); 158 1.12 uch val &= ~TX3912_VIDEOCTRL1_INVVID; 159 1.12 uch tx_conf_write(tc, TX3912_VIDEOCTRL1_REG, val); 160 1.12 uch 161 1.12 uch /* install default CLUT */ 162 1.12 uch tx3912video_clut_init(sc); 163 1.12 uch 164 1.10 uch /* if serial console, power off video module */ 165 1.19 uch tx3912video_power(sc, 0, 0, (void *) 166 1.23 uch (console ? PWR_RESUME : PWR_SUSPEND)); 167 1.19 uch 168 1.18 uch /* Add a hard power hook to power saving */ 169 1.18 uch sc->sc_powerhook = config_hook(CONFIG_HOOK_PMEVENT, 170 1.23 uch CONFIG_HOOK_PMEVENT_HARDPOWER, CONFIG_HOOK_SHARE, 171 1.23 uch tx3912video_power, sc); 172 1.18 uch if (sc->sc_powerhook == 0) 173 1.18 uch printf("WARNING unable to establish hard power hook"); 174 1.6 uch 175 1.13 uch #ifdef TX3912VIDEO_DEBUG 176 1.10 uch /* attach debug draw routine (debugging use) */ 177 1.15 uch video_attach_drawfunc(sc->sc_chip); 178 1.15 uch tx_conf_register_video(tc, sc->sc_chip); 179 1.13 uch #endif 180 1.10 uch 181 1.1 uch /* Attach frame buffer device */ 182 1.11 uch tx3912video_hpcfbinit(sc); 183 1.11 uch 184 1.11 uch if (console && hpcfb_cnattach(&sc->sc_fbconf) != 0) { 185 1.11 uch panic("tx3912video_attach: can't init fb console"); 186 1.2 uch } 187 1.11 uch 188 1.11 uch ha.ha_console = console; 189 1.11 uch ha.ha_accessops = &tx3912video_ha; 190 1.11 uch ha.ha_accessctx = sc; 191 1.11 uch ha.ha_curfbconf = 0; 192 1.11 uch ha.ha_nfbconf = 1; 193 1.11 uch ha.ha_fbconflist = &sc->sc_fbconf; 194 1.11 uch ha.ha_curdspconf = 0; 195 1.11 uch ha.ha_ndspconf = 1; 196 1.11 uch ha.ha_dspconflist = &sc->sc_dspconf; 197 1.11 uch 198 1.47 thorpej config_found(self, &ha, hpcfbprint, CFARGS_NONE); 199 1.26 uch #if NBIVIDEO > 0 200 1.26 uch /* bivideo is no longer need */ 201 1.26 uch bivideo_dont_attach = 1; 202 1.26 uch #endif /* NBIVIDEO > 0 */ 203 1.1 uch } 204 1.1 uch 205 1.18 uch int 206 1.18 uch tx3912video_power(void *ctx, int type, long id, void *msg) 207 1.18 uch { 208 1.18 uch struct tx3912video_softc *sc = ctx; 209 1.18 uch struct video_chip *chip = sc->sc_chip; 210 1.18 uch tx_chipset_tag_t tc = chip->vc_v; 211 1.18 uch int why = (int)msg; 212 1.18 uch txreg_t val; 213 1.18 uch 214 1.18 uch switch (why) { 215 1.18 uch case PWR_RESUME: 216 1.19 uch if (!sc->sc_console) 217 1.23 uch return (0); /* serial console */ 218 1.19 uch 219 1.42 chs DPRINTF(("%s: ON\n", device_xname(sc->sc_dev))); 220 1.18 uch val = tx_conf_read(tc, TX3912_VIDEOCTRL1_REG); 221 1.18 uch val |= (TX3912_VIDEOCTRL1_DISPON | TX3912_VIDEOCTRL1_ENVID); 222 1.18 uch tx_conf_write(tc, TX3912_VIDEOCTRL1_REG, val); 223 1.18 uch break; 224 1.18 uch case PWR_SUSPEND: 225 1.18 uch /* FALLTHROUGH */ 226 1.18 uch case PWR_STANDBY: 227 1.42 chs DPRINTF(("%s: OFF\n", device_xname(sc->sc_dev))); 228 1.18 uch val = tx_conf_read(tc, TX3912_VIDEOCTRL1_REG); 229 1.18 uch val &= ~(TX3912_VIDEOCTRL1_DISPON | TX3912_VIDEOCTRL1_ENVID); 230 1.18 uch tx_conf_write(tc, TX3912_VIDEOCTRL1_REG, val); 231 1.18 uch break; 232 1.18 uch } 233 1.18 uch 234 1.23 uch return (0); 235 1.18 uch } 236 1.18 uch 237 1.11 uch void 238 1.40 dsl tx3912video_hpcfbinit(struct tx3912video_softc *sc) 239 1.1 uch { 240 1.15 uch struct video_chip *chip = sc->sc_chip; 241 1.11 uch struct hpcfb_fbconf *fb = &sc->sc_fbconf; 242 1.15 uch vaddr_t fbvaddr = (vaddr_t)MIPS_PHYS_TO_KSEG1(chip->vc_fbpaddr); 243 1.11 uch 244 1.11 uch memset(fb, 0, sizeof(struct hpcfb_fbconf)); 245 1.11 uch 246 1.11 uch fb->hf_conf_index = 0; /* configuration index */ 247 1.11 uch fb->hf_nconfs = 1; /* how many configurations */ 248 1.12 uch strncpy(fb->hf_name, "TX3912 built-in video", HPCFB_MAXNAMELEN); 249 1.11 uch /* frame buffer name */ 250 1.12 uch strncpy(fb->hf_conf_name, "LCD", HPCFB_MAXNAMELEN); 251 1.11 uch /* configuration name */ 252 1.11 uch fb->hf_height = chip->vc_fbheight; 253 1.11 uch fb->hf_width = chip->vc_fbwidth; 254 1.21 takemura fb->hf_baseaddr = (u_long)fbvaddr; 255 1.21 takemura fb->hf_offset = (u_long)fbvaddr - 256 1.23 uch mips_ptob(mips_btop(fbvaddr)); 257 1.11 uch /* frame buffer start offset */ 258 1.12 uch fb->hf_bytes_per_line = (chip->vc_fbwidth * chip->vc_fbdepth) 259 1.23 uch / NBBY; 260 1.11 uch fb->hf_nplanes = 1; 261 1.11 uch fb->hf_bytes_per_plane = chip->vc_fbheight * fb->hf_bytes_per_line; 262 1.11 uch 263 1.11 uch fb->hf_access_flags |= HPCFB_ACCESS_BYTE; 264 1.11 uch fb->hf_access_flags |= HPCFB_ACCESS_WORD; 265 1.11 uch fb->hf_access_flags |= HPCFB_ACCESS_DWORD; 266 1.20 uch if (video_reverse_color()) 267 1.20 uch fb->hf_access_flags |= HPCFB_ACCESS_REVERSE; 268 1.20 uch 269 1.11 uch 270 1.11 uch switch (chip->vc_fbdepth) { 271 1.11 uch default: 272 1.31 provos panic("tx3912video_hpcfbinit: not supported color depth"); 273 1.11 uch /* NOTREACHED */ 274 1.11 uch case 2: 275 1.11 uch fb->hf_class = HPCFB_CLASS_GRAYSCALE; 276 1.11 uch fb->hf_access_flags |= HPCFB_ACCESS_STATIC; 277 1.11 uch fb->hf_pack_width = 8; 278 1.11 uch fb->hf_pixels_per_pack = 4; 279 1.11 uch fb->hf_pixel_width = 2; 280 1.11 uch fb->hf_class_data_length = sizeof(struct hf_gray_tag); 281 1.14 uch /* reserved for future use */ 282 1.14 uch fb->hf_u.hf_gray.hf_flags = 0; 283 1.11 uch break; 284 1.11 uch case 8: 285 1.12 uch fb->hf_class = HPCFB_CLASS_INDEXCOLOR; 286 1.11 uch fb->hf_access_flags |= HPCFB_ACCESS_STATIC; 287 1.11 uch fb->hf_pack_width = 8; 288 1.11 uch fb->hf_pixels_per_pack = 1; 289 1.11 uch fb->hf_pixel_width = 8; 290 1.11 uch fb->hf_class_data_length = sizeof(struct hf_indexed_tag); 291 1.14 uch /* reserved for future use */ 292 1.14 uch fb->hf_u.hf_indexed.hf_flags = 0; 293 1.11 uch break; 294 1.11 uch } 295 1.1 uch } 296 1.1 uch 297 1.1 uch int 298 1.18 uch tx3912video_init(paddr_t fb_start, paddr_t *fb_end) 299 1.10 uch { 300 1.15 uch struct video_chip *chip = &tx3912video_chip; 301 1.1 uch tx_chipset_tag_t tc; 302 1.7 uch txreg_t reg; 303 1.19 uch int fbdepth, reverse, error; 304 1.1 uch 305 1.19 uch reverse = video_reverse_color(); 306 1.15 uch chip->vc_v = tc = tx_conf_get_tag(); 307 1.10 uch 308 1.10 uch reg = tx_conf_read(tc, TX3912_VIDEOCTRL1_REG); 309 1.10 uch fbdepth = 1 << (TX3912_VIDEOCTRL1_BITSEL(reg)); 310 1.7 uch 311 1.10 uch switch (fbdepth) { 312 1.7 uch case 2: 313 1.19 uch bootinfo->fb_type = reverse ? BIFB_D2_M2L_3 : BIFB_D2_M2L_0; 314 1.7 uch break; 315 1.7 uch case 4: 316 1.7 uch /* XXX should implement rasops4.c */ 317 1.10 uch fbdepth = 2; 318 1.19 uch bootinfo->fb_type = reverse ? BIFB_D2_M2L_3 : BIFB_D2_M2L_0; 319 1.7 uch reg = tx_conf_read(tc, TX3912_VIDEOCTRL1_REG); 320 1.7 uch TX3912_VIDEOCTRL1_BITSEL_CLR(reg); 321 1.23 uch reg = TX3912_VIDEOCTRL1_BITSEL_SET(reg, 322 1.23 uch TX3912_VIDEOCTRL1_BITSEL_2BITGREYSCALE); 323 1.7 uch tx_conf_write(tc, TX3912_VIDEOCTRL1_REG, reg); 324 1.7 uch break; 325 1.7 uch case 8: 326 1.19 uch bootinfo->fb_type = reverse ? BIFB_D8_FF : BIFB_D8_00; 327 1.7 uch break; 328 1.7 uch } 329 1.7 uch 330 1.15 uch chip->vc_fbdepth = fbdepth; 331 1.15 uch chip->vc_fbwidth = bootinfo->fb_width; 332 1.15 uch chip->vc_fbheight= bootinfo->fb_height; 333 1.7 uch 334 1.1 uch /* Allocate framebuffer area */ 335 1.10 uch error = tx3912video_framebuffer_alloc(chip, fb_start, fb_end); 336 1.10 uch if (error != 0) 337 1.10 uch return (1); 338 1.10 uch 339 1.1 uch #if notyet 340 1.10 uch tx3912video_resolution_init(chip); 341 1.1 uch #else 342 1.1 uch /* Use Windows CE setting. */ 343 1.1 uch #endif 344 1.1 uch /* Set DMA transfer address to VID module */ 345 1.10 uch tx3912video_framebuffer_init(chip); 346 1.1 uch 347 1.48 andvar /* Synchronize framebuffer addr to frame signal */ 348 1.10 uch tx3912video_reset(chip); 349 1.1 uch 350 1.10 uch bootinfo->fb_line_bytes = (chip->vc_fbwidth * fbdepth) / NBBY; 351 1.15 uch bootinfo->fb_addr = (void *)MIPS_PHYS_TO_KSEG1(chip->vc_fbpaddr); 352 1.10 uch 353 1.10 uch return (0); 354 1.1 uch } 355 1.1 uch 356 1.23 uch int 357 1.18 uch tx3912video_framebuffer_alloc(struct video_chip *chip, paddr_t fb_start, 358 1.23 uch paddr_t *fb_end /* buffer allocation hint */) 359 1.1 uch { 360 1.10 uch struct extent_fixed ex_fixed[10]; 361 1.1 uch struct extent *ex; 362 1.1 uch u_long addr, size; 363 1.10 uch int error; 364 1.10 uch 365 1.49 andvar /* calculate frame buffer size */ 366 1.10 uch size = (chip->vc_fbwidth * chip->vc_fbheight * chip->vc_fbdepth) / 367 1.23 uch NBBY; 368 1.10 uch 369 1.10 uch /* extent V-RAM region */ 370 1.10 uch ex = extent_create("Frame buffer address", fb_start, *fb_end, 371 1.41 para (void *)ex_fixed, sizeof ex_fixed, 372 1.23 uch EX_NOWAIT); 373 1.10 uch if (ex == 0) 374 1.10 uch return (1); 375 1.1 uch 376 1.1 uch /* Allocate V-RAM area */ 377 1.14 uch error = extent_alloc_subregion(ex, fb_start, fb_start + size - 1, 378 1.23 uch size, TX3912_FRAMEBUFFER_ALIGNMENT, 379 1.23 uch TX3912_FRAMEBUFFER_BOUNDARY, EX_FAST|EX_NOWAIT, &addr); 380 1.10 uch extent_destroy(ex); 381 1.10 uch 382 1.23 uch if (error != 0) 383 1.10 uch return (1); 384 1.10 uch 385 1.15 uch chip->vc_fbpaddr = addr; 386 1.15 uch chip->vc_fbvaddr = MIPS_PHYS_TO_KSEG1(addr); 387 1.10 uch chip->vc_fbsize = size; 388 1.6 uch 389 1.10 uch *fb_end = addr + size; 390 1.1 uch 391 1.10 uch return (0); 392 1.1 uch } 393 1.1 uch 394 1.18 uch void 395 1.18 uch tx3912video_framebuffer_init(struct video_chip *chip) 396 1.1 uch { 397 1.10 uch u_int32_t fb_addr, fb_size, vaddr, bank, base; 398 1.10 uch txreg_t reg; 399 1.15 uch tx_chipset_tag_t tc = chip->vc_v; 400 1.10 uch 401 1.15 uch fb_addr = chip->vc_fbpaddr; 402 1.10 uch fb_size = chip->vc_fbsize; 403 1.1 uch 404 1.1 uch /* XXX currently I don't set DFVAL, so force DF signal toggled on 405 1.1 uch * XXX each frame. */ 406 1.1 uch reg = tx_conf_read(tc, TX3912_VIDEOCTRL1_REG); 407 1.1 uch reg &= ~TX3912_VIDEOCTRL1_DFMODE; 408 1.1 uch tx_conf_write(tc, TX3912_VIDEOCTRL1_REG, reg); 409 1.1 uch 410 1.1 uch /* Set DMA transfer start and end address */ 411 1.10 uch 412 1.1 uch bank = TX3912_VIDEOCTRL3_VIDBANK(fb_addr); 413 1.1 uch base = TX3912_VIDEOCTRL3_VIDBASEHI(fb_addr); 414 1.1 uch reg = TX3912_VIDEOCTRL3_VIDBANK_SET(0, bank); 415 1.1 uch /* Upper address counter */ 416 1.1 uch reg = TX3912_VIDEOCTRL3_VIDBASEHI_SET(reg, base); 417 1.1 uch tx_conf_write(tc, TX3912_VIDEOCTRL3_REG, reg); 418 1.1 uch 419 1.1 uch /* Lower address counter */ 420 1.1 uch base = TX3912_VIDEOCTRL4_VIDBASELO(fb_addr + fb_size); 421 1.1 uch reg = TX3912_VIDEOCTRL4_VIDBASELO_SET(0, base); 422 1.1 uch 423 1.1 uch /* Set DF-signal rate */ 424 1.1 uch reg = TX3912_VIDEOCTRL4_DFVAL_SET(reg, 0); /* XXX not yet*/ 425 1.1 uch 426 1.1 uch /* Set VIDDONE signal delay after FRAME signal */ 427 1.1 uch /* XXX not yet*/ 428 1.1 uch tx_conf_write(tc, TX3912_VIDEOCTRL4_REG, reg); 429 1.1 uch 430 1.1 uch /* Clear frame buffer */ 431 1.1 uch vaddr = MIPS_PHYS_TO_KSEG1(fb_addr); 432 1.10 uch memset((void*)vaddr, 0, fb_size); 433 1.1 uch } 434 1.1 uch 435 1.18 uch void 436 1.18 uch tx3912video_resolution_init(struct video_chip *chip) 437 1.1 uch { 438 1.43 he int h, v, split, horzval, lineval; 439 1.15 uch tx_chipset_tag_t tc = chip->vc_v; 440 1.10 uch txreg_t reg; 441 1.10 uch u_int32_t val; 442 1.10 uch 443 1.10 uch h = chip->vc_fbwidth; 444 1.10 uch v = chip->vc_fbheight; 445 1.1 uch reg = tx_conf_read(tc, TX3912_VIDEOCTRL1_REG); 446 1.1 uch split = reg & TX3912_VIDEOCTRL1_DISPSPLIT; 447 1.1 uch val = TX3912_VIDEOCTRL1_BITSEL(reg); 448 1.1 uch 449 1.23 uch if ((val == TX3912_VIDEOCTRL1_BITSEL_8BITCOLOR) && !split) { 450 1.3 uch /* (LCD horizontal pixels / 8bit) * RGB - 1 */ 451 1.3 uch horzval = (h / 8) * 3 - 1; 452 1.1 uch } else { 453 1.1 uch horzval = h / 4 - 1; 454 1.1 uch } 455 1.1 uch lineval = (split ? v / 2 : v) - 1; 456 1.1 uch 457 1.1 uch /* Video rate */ 458 1.3 uch /* XXX 459 1.3 uch * probably This value should be determined from DFINT and LCDINT 460 1.3 uch */ 461 1.1 uch reg = TX3912_VIDEOCTRL2_VIDRATE_SET(0, horzval + 1); 462 1.1 uch /* Horizontal size of LCD */ 463 1.1 uch reg = TX3912_VIDEOCTRL2_HORZVAL_SET(reg, horzval); 464 1.1 uch /* # of lines for the LCD */ 465 1.1 uch reg = TX3912_VIDEOCTRL2_LINEVAL_SET(reg, lineval); 466 1.1 uch 467 1.1 uch tx_conf_write(tc, TX3912_VIDEOCTRL2_REG, reg); 468 1.1 uch } 469 1.1 uch 470 1.1 uch void 471 1.18 uch tx3912video_reset(struct video_chip *chip) 472 1.1 uch { 473 1.15 uch tx_chipset_tag_t tc = chip->vc_v; 474 1.10 uch txreg_t reg; 475 1.1 uch 476 1.1 uch reg = tx_conf_read(tc, TX3912_VIDEOCTRL1_REG); 477 1.3 uch 478 1.1 uch /* Disable video logic at end of this frame */ 479 1.1 uch reg |= TX3912_VIDEOCTRL1_ENFREEZEFRAME; 480 1.1 uch tx_conf_write(tc, TX3912_VIDEOCTRL1_REG, reg); 481 1.3 uch 482 1.1 uch /* Wait for end of frame */ 483 1.10 uch delay(30 * 1000); 484 1.3 uch 485 1.1 uch /* Make sure to disable video logic */ 486 1.1 uch reg &= ~TX3912_VIDEOCTRL1_ENVID; 487 1.1 uch tx_conf_write(tc, TX3912_VIDEOCTRL1_REG, reg); 488 1.3 uch 489 1.1 uch delay(1000); 490 1.3 uch 491 1.1 uch /* Enable video logic again */ 492 1.1 uch reg &= ~TX3912_VIDEOCTRL1_ENFREEZEFRAME; 493 1.1 uch reg |= TX3912_VIDEOCTRL1_ENVID; 494 1.1 uch tx_conf_write(tc, TX3912_VIDEOCTRL1_REG, reg); 495 1.3 uch 496 1.1 uch delay(1000); 497 1.1 uch } 498 1.1 uch 499 1.11 uch int 500 1.38 christos tx3912video_ioctl(void *v, u_long cmd, void *data, int flag, struct lwp *l) 501 1.11 uch { 502 1.11 uch struct tx3912video_softc *sc = (struct tx3912video_softc *)v; 503 1.11 uch struct hpcfb_fbconf *fbconf; 504 1.11 uch struct hpcfb_dspconf *dspconf; 505 1.12 uch struct wsdisplay_cmap *cmap; 506 1.12 uch u_int8_t *r, *g, *b; 507 1.12 uch u_int32_t *rgb; 508 1.12 uch int idx, cnt, error; 509 1.11 uch 510 1.11 uch switch (cmd) { 511 1.11 uch case WSDISPLAYIO_GETCMAP: 512 1.35 chs cmap = (struct wsdisplay_cmap *)data; 513 1.12 uch cnt = cmap->count; 514 1.12 uch idx = cmap->index; 515 1.12 uch 516 1.12 uch if (sc->sc_fbconf.hf_class != HPCFB_CLASS_INDEXCOLOR || 517 1.23 uch sc->sc_fbconf.hf_pack_width != 8 || 518 1.23 uch !LEGAL_CLUT_INDEX(idx) || 519 1.35 chs !LEGAL_CLUT_INDEX(idx + cnt - 1)) { 520 1.12 uch return (EINVAL); 521 1.12 uch } 522 1.12 uch 523 1.12 uch error = cmap_work_alloc(&r, &g, &b, &rgb, cnt); 524 1.35 chs if (error) 525 1.35 chs goto out; 526 1.12 uch tx3912video_clut_get(sc, rgb, idx, cnt); 527 1.12 uch rgb24_decompose(rgb, r, g, b, cnt); 528 1.12 uch 529 1.35 chs error = copyout(r, cmap->red, cnt); 530 1.35 chs if (error) 531 1.35 chs goto out; 532 1.35 chs error = copyout(g, cmap->green,cnt); 533 1.35 chs if (error) 534 1.35 chs goto out; 535 1.35 chs error = copyout(b, cmap->blue, cnt); 536 1.12 uch 537 1.35 chs out: 538 1.12 uch cmap_work_free(r, g, b, rgb); 539 1.35 chs return error; 540 1.11 uch 541 1.11 uch case WSDISPLAYIO_PUTCMAP: 542 1.12 uch /* 543 1.12 uch * TX3912 can't change CLUT index. R:G:B = 3:3:2 544 1.12 uch */ 545 1.14 uch return (0); 546 1.11 uch 547 1.11 uch case HPCFBIO_GCONF: 548 1.11 uch fbconf = (struct hpcfb_fbconf *)data; 549 1.11 uch if (fbconf->hf_conf_index != 0 && 550 1.11 uch fbconf->hf_conf_index != HPCFB_CURRENT_CONFIG) { 551 1.11 uch return (EINVAL); 552 1.11 uch } 553 1.11 uch *fbconf = sc->sc_fbconf; /* structure assignment */ 554 1.11 uch return (0); 555 1.11 uch 556 1.11 uch case HPCFBIO_SCONF: 557 1.11 uch fbconf = (struct hpcfb_fbconf *)data; 558 1.11 uch if (fbconf->hf_conf_index != 0 && 559 1.11 uch fbconf->hf_conf_index != HPCFB_CURRENT_CONFIG) { 560 1.11 uch return (EINVAL); 561 1.11 uch } 562 1.11 uch /* 563 1.36 abs * nothing to do because we have only one configuration 564 1.11 uch */ 565 1.11 uch return (0); 566 1.11 uch 567 1.11 uch case HPCFBIO_GDSPCONF: 568 1.11 uch dspconf = (struct hpcfb_dspconf *)data; 569 1.11 uch if ((dspconf->hd_unit_index != 0 && 570 1.23 uch dspconf->hd_unit_index != HPCFB_CURRENT_UNIT) || 571 1.11 uch (dspconf->hd_conf_index != 0 && 572 1.23 uch dspconf->hd_conf_index != HPCFB_CURRENT_CONFIG)) { 573 1.11 uch return (EINVAL); 574 1.11 uch } 575 1.11 uch *dspconf = sc->sc_dspconf; /* structure assignment */ 576 1.11 uch return (0); 577 1.11 uch 578 1.11 uch case HPCFBIO_SDSPCONF: 579 1.11 uch dspconf = (struct hpcfb_dspconf *)data; 580 1.11 uch if ((dspconf->hd_unit_index != 0 && 581 1.23 uch dspconf->hd_unit_index != HPCFB_CURRENT_UNIT) || 582 1.11 uch (dspconf->hd_conf_index != 0 && 583 1.23 uch dspconf->hd_conf_index != HPCFB_CURRENT_CONFIG)) { 584 1.11 uch return (EINVAL); 585 1.11 uch } 586 1.11 uch /* 587 1.11 uch * nothing to do 588 1.36 abs * because we have only one unit and one configuration 589 1.11 uch */ 590 1.11 uch return (0); 591 1.11 uch 592 1.11 uch case HPCFBIO_GOP: 593 1.11 uch case HPCFBIO_SOP: 594 1.11 uch /* XXX not implemented yet */ 595 1.11 uch return (EINVAL); 596 1.11 uch } 597 1.11 uch 598 1.27 atatat return (EPASSTHROUGH); 599 1.11 uch } 600 1.11 uch 601 1.16 simonb paddr_t 602 1.18 uch tx3912video_mmap(void *ctx, off_t offset, int prot) 603 1.11 uch { 604 1.11 uch struct tx3912video_softc *sc = (struct tx3912video_softc *)ctx; 605 1.11 uch 606 1.11 uch if (offset < 0 || (sc->sc_fbconf.hf_bytes_per_plane + 607 1.23 uch sc->sc_fbconf.hf_offset) < offset) { 608 1.11 uch return (-1); 609 1.11 uch } 610 1.11 uch 611 1.15 uch return (mips_btop(sc->sc_chip->vc_fbpaddr + offset)); 612 1.12 uch } 613 1.12 uch 614 1.12 uch /* 615 1.12 uch * CLUT staff 616 1.12 uch */ 617 1.12 uch static const struct { 618 1.12 uch int mul, div; 619 1.12 uch } dither_list [] = { 620 1.12 uch [TX3912_VIDEO_DITHER_DUTYCYCLE_1] = { 1, 1 }, 621 1.12 uch [TX3912_VIDEO_DITHER_DUTYCYCLE_6_7] = { 6, 7 }, 622 1.12 uch [TX3912_VIDEO_DITHER_DUTYCYCLE_4_5] = { 4, 5 }, 623 1.12 uch [TX3912_VIDEO_DITHER_DUTYCYCLE_3_4] = { 3, 4 }, 624 1.12 uch [TX3912_VIDEO_DITHER_DUTYCYCLE_5_7] = { 5, 7 }, 625 1.12 uch [TX3912_VIDEO_DITHER_DUTYCYCLE_2_3] = { 2, 3 }, 626 1.12 uch [TX3912_VIDEO_DITHER_DUTYCYCLE_3_5] = { 3, 5 }, 627 1.12 uch [TX3912_VIDEO_DITHER_DUTYCYCLE_4_7] = { 4, 7 }, 628 1.12 uch [TX3912_VIDEO_DITHER_DUTYCYCLE_2_4] = { 2, 4 }, 629 1.12 uch [TX3912_VIDEO_DITHER_DUTYCYCLE_3_7] = { 3, 7 }, 630 1.12 uch [TX3912_VIDEO_DITHER_DUTYCYCLE_2_5] = { 2, 5 }, 631 1.12 uch [TX3912_VIDEO_DITHER_DUTYCYCLE_1_3] = { 1, 3 }, 632 1.12 uch [TX3912_VIDEO_DITHER_DUTYCYCLE_2_7] = { 2, 7 }, 633 1.12 uch [TX3912_VIDEO_DITHER_DUTYCYCLE_1_5] = { 1, 5 }, 634 1.12 uch [TX3912_VIDEO_DITHER_DUTYCYCLE_1_7] = { 1, 7 }, 635 1.12 uch [TX3912_VIDEO_DITHER_DUTYCYCLE_0] = { 0, 1 } 636 1.12 uch }, *dlp; 637 1.12 uch 638 1.12 uch static const int dither_level8[8] = { 639 1.12 uch TX3912_VIDEO_DITHER_DUTYCYCLE_0, 640 1.12 uch TX3912_VIDEO_DITHER_DUTYCYCLE_2_7, 641 1.12 uch TX3912_VIDEO_DITHER_DUTYCYCLE_2_5, 642 1.12 uch TX3912_VIDEO_DITHER_DUTYCYCLE_2_4, 643 1.12 uch TX3912_VIDEO_DITHER_DUTYCYCLE_3_5, 644 1.12 uch TX3912_VIDEO_DITHER_DUTYCYCLE_5_7, 645 1.12 uch TX3912_VIDEO_DITHER_DUTYCYCLE_4_5, 646 1.12 uch TX3912_VIDEO_DITHER_DUTYCYCLE_1, 647 1.12 uch }; 648 1.12 uch 649 1.12 uch static const int dither_level4[4] = { 650 1.12 uch TX3912_VIDEO_DITHER_DUTYCYCLE_0, 651 1.12 uch TX3912_VIDEO_DITHER_DUTYCYCLE_1_3, 652 1.12 uch TX3912_VIDEO_DITHER_DUTYCYCLE_5_7, 653 1.12 uch TX3912_VIDEO_DITHER_DUTYCYCLE_1, 654 1.12 uch }; 655 1.12 uch 656 1.12 uch static int 657 1.18 uch __get_color8(int luti) 658 1.12 uch { 659 1.12 uch KASSERT(luti >=0 && luti < 8); 660 1.12 uch dlp = &dither_list[dither_level8[luti]]; 661 1.12 uch 662 1.12 uch return ((0xff * dlp->mul) / dlp->div); 663 1.12 uch } 664 1.12 uch 665 1.12 uch static int 666 1.18 uch __get_color4(int luti) 667 1.12 uch { 668 1.12 uch KASSERT(luti >=0 && luti < 4); 669 1.12 uch dlp = &dither_list[dither_level4[luti]]; 670 1.12 uch 671 1.12 uch return ((0xff * dlp->mul) / dlp->div); 672 1.12 uch } 673 1.12 uch 674 1.12 uch void 675 1.18 uch tx3912video_clut_get(struct tx3912video_softc *sc, u_int32_t *rgb, int beg, 676 1.23 uch int cnt) 677 1.12 uch { 678 1.12 uch int i; 679 1.12 uch 680 1.12 uch KASSERT(rgb); 681 1.12 uch KASSERT(LEGAL_CLUT_INDEX(beg)); 682 1.12 uch KASSERT(LEGAL_CLUT_INDEX(beg + cnt - 1)); 683 1.12 uch 684 1.14 uch for (i = beg; i < beg + cnt; i++) { 685 1.14 uch *rgb++ = RGB24(__get_color8((i >> 5) & 0x7), 686 1.23 uch __get_color8((i >> 2) & 0x7), 687 1.23 uch __get_color4(i & 0x3)); 688 1.12 uch } 689 1.12 uch } 690 1.12 uch 691 1.12 uch void 692 1.18 uch tx3912video_clut_install(void *ctx, struct rasops_info *ri) 693 1.12 uch { 694 1.12 uch struct tx3912video_softc *sc = ctx; 695 1.29 yamt static const int system_cmap[0x10] = { 696 1.12 uch TX3912VIDEO_BLACK, 697 1.12 uch TX3912VIDEO_RED, 698 1.12 uch TX3912VIDEO_GREEN, 699 1.12 uch TX3912VIDEO_YELLOW, 700 1.12 uch TX3912VIDEO_BLUE, 701 1.12 uch TX3912VIDEO_MAGENTA, 702 1.12 uch TX3912VIDEO_CYAN, 703 1.12 uch TX3912VIDEO_WHITE, 704 1.12 uch TX3912VIDEO_DARK_BLACK, 705 1.12 uch TX3912VIDEO_DARK_RED, 706 1.12 uch TX3912VIDEO_DARK_GREEN, 707 1.12 uch TX3912VIDEO_DARK_YELLOW, 708 1.12 uch TX3912VIDEO_DARK_BLUE, 709 1.12 uch TX3912VIDEO_DARK_MAGENTA, 710 1.12 uch TX3912VIDEO_DARK_CYAN, 711 1.12 uch TX3912VIDEO_DARK_WHITE, 712 1.12 uch }; 713 1.12 uch 714 1.12 uch KASSERT(ri); 715 1.12 uch 716 1.12 uch if (sc->sc_chip->vc_fbdepth == 8) { 717 1.12 uch /* XXX 2bit gray scale LUT not supported */ 718 1.12 uch memcpy(ri->ri_devcmap, system_cmap, sizeof system_cmap); 719 1.12 uch } 720 1.12 uch } 721 1.12 uch 722 1.12 uch void 723 1.18 uch tx3912video_clut_init(struct tx3912video_softc *sc) 724 1.12 uch { 725 1.15 uch tx_chipset_tag_t tc = sc->sc_chip->vc_v; 726 1.12 uch 727 1.12 uch if (sc->sc_chip->vc_fbdepth != 8) { 728 1.12 uch return; /* XXX 2bit gray scale LUT not supported */ 729 1.12 uch } 730 1.12 uch 731 1.12 uch /* 732 1.12 uch * time-based dithering pattern (TOSHIBA recommended pattern) 733 1.12 uch */ 734 1.12 uch /* 2/3, 1/3 */ 735 1.12 uch tx_conf_write(tc, TX3912_VIDEOCTRL8_REG, 736 1.23 uch TX3912_VIDEOCTRL8_PAT2_3_DEFAULT); 737 1.12 uch /* 3/4, 2/4 */ 738 1.12 uch tx_conf_write(tc, TX3912_VIDEOCTRL9_REG, 739 1.23 uch (TX3912_VIDEOCTRL9_PAT3_4_DEFAULT << 16) | 740 1.23 uch TX3912_VIDEOCTRL9_PAT2_4_DEFAULT); 741 1.12 uch /* 4/5, 1/5 */ 742 1.12 uch tx_conf_write(tc, TX3912_VIDEOCTRL10_REG, 743 1.23 uch TX3912_VIDEOCTRL10_PAT4_5_DEFAULT); 744 1.12 uch /* 3/5, 2/5 */ 745 1.12 uch tx_conf_write(tc, TX3912_VIDEOCTRL11_REG, 746 1.23 uch TX3912_VIDEOCTRL11_PAT3_5_DEFAULT); 747 1.12 uch /* 6/7, 1/7 */ 748 1.12 uch tx_conf_write(tc, TX3912_VIDEOCTRL12_REG, 749 1.23 uch TX3912_VIDEOCTRL12_PAT6_7_DEFAULT); 750 1.12 uch /* 5/7, 2/7 */ 751 1.12 uch tx_conf_write(tc, TX3912_VIDEOCTRL13_REG, 752 1.23 uch TX3912_VIDEOCTRL13_PAT5_7_DEFAULT); 753 1.12 uch /* 4/7, 3/7 */ 754 1.12 uch tx_conf_write(tc, TX3912_VIDEOCTRL14_REG, 755 1.23 uch TX3912_VIDEOCTRL14_PAT4_7_DEFAULT); 756 1.12 uch 757 1.12 uch /* 758 1.12 uch * dither-pattern look-up table. (selected by uch) 759 1.12 uch */ 760 1.12 uch /* red */ 761 1.12 uch tx_conf_write(tc, TX3912_VIDEOCTRL5_REG, 762 1.23 uch (dither_level8[7] << 28) | 763 1.23 uch (dither_level8[6] << 24) | 764 1.23 uch (dither_level8[5] << 20) | 765 1.23 uch (dither_level8[4] << 16) | 766 1.23 uch (dither_level8[3] << 12) | 767 1.23 uch (dither_level8[2] << 8) | 768 1.23 uch (dither_level8[1] << 4) | 769 1.23 uch (dither_level8[0] << 0)); 770 1.12 uch /* green */ 771 1.12 uch tx_conf_write(tc, TX3912_VIDEOCTRL6_REG, 772 1.23 uch (dither_level8[7] << 28) | 773 1.23 uch (dither_level8[6] << 24) | 774 1.23 uch (dither_level8[5] << 20) | 775 1.23 uch (dither_level8[4] << 16) | 776 1.23 uch (dither_level8[3] << 12) | 777 1.23 uch (dither_level8[2] << 8) | 778 1.23 uch (dither_level8[1] << 4) | 779 1.23 uch (dither_level8[0] << 0)); 780 1.12 uch /* blue (2bit gray scale also use this look-up table) */ 781 1.12 uch tx_conf_write(tc, TX3912_VIDEOCTRL7_REG, 782 1.23 uch (dither_level4[3] << 12) | 783 1.23 uch (dither_level4[2] << 8) | 784 1.23 uch (dither_level4[1] << 4) | 785 1.23 uch (dither_level4[0] << 0)); 786 1.14 uch 787 1.14 uch tx3912video_reset(sc->sc_chip); 788 1.6 uch } 789