1 /* $NetBSD: ipaq_lcd.c,v 1.7 2002/03/17 19:40:38 atatat Exp $ */ 2 #define IPAQ_LCD_DEBUG 3 4 /* 5 * Copyright (c) 2001 The NetBSD Foundation, Inc. 6 * All rights reserved. 7 * 8 * This code is derived from software contributed to The NetBSD Foundation 9 * by Ichiro FUKUHARA (ichiro@ichiro.org). 10 * 11 * Redistribution and use in source and binary forms, with or without 12 * modification, are permitted provided that the following conditions 13 * are met: 14 * 1. Redistributions of source code must retain the above copyright 15 * notice, this list of conditions and the following disclaimer. 16 * 2. Redistributions in binary form must reproduce the above copyright 17 * notice, this list of conditions and the following disclaimer in the 18 * documentation and/or other materials provided with the distribution. 19 * 3. All advertising materials mentioning features or use of this software 20 * must display the following acknowledgement: 21 * This product includes software developed by the NetBSD 22 * Foundation, Inc. and its contributors. 23 * 4. Neither the name of The NetBSD Foundation nor the names of its 24 * contributors may be used to endorse or promote products derived 25 * from this software without specific prior written permission. 26 * 27 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 28 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 29 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 30 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 31 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 32 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 33 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 34 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 35 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 36 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 37 * POSSIBILITY OF SUCH DAMAGE. 38 */ 39 40 #include <sys/types.h> 41 #include <sys/param.h> 42 #include <sys/systm.h> 43 #include <sys/kernel.h> 44 #include <sys/time.h> 45 #include <sys/device.h> 46 47 #include <uvm/uvm_extern.h> 48 49 #include <dev/wscons/wsconsio.h> 50 51 #include <machine/bootinfo.h> 52 #include <machine/bus.h> 53 #include <machine/intr.h> 54 #include <arm/cpufunc.h> 55 #include <arm/arm32/katelib.h> 56 57 #include <hpcarm/sa11x0/sa11x0_reg.h> 58 #include <hpcarm/sa11x0/sa11x0_gpioreg.h> 59 60 #include <hpcarm/dev/ipaq_gpioreg.h> 61 #include <hpcarm/dev/ipaq_saipvar.h> 62 #include <hpcarm/dev/ipaq_lcdreg.h> 63 #include <hpcarm/dev/ipaq_lcdvar.h> 64 65 #ifdef IPAQ_LCD_DEBUG 66 #define DPRINTFN(n, x) if (ipaqlcddebug > (n)) printf x 67 int ipaqlcddebug = 0xff; 68 #else 69 #define DPRINTFN(n, x) 70 #endif 71 #define DPRINTF(x) DPRINTFN(0, x) 72 73 static int ipaqlcd_match(struct device *, struct cfdata *, void *); 74 static void ipaqlcd_attach(struct device *, struct device *, void *); 75 static void ipaqlcd_init(struct ipaqlcd_softc *); 76 static int ipaqlcd_fbinit(struct ipaqlcd_softc *); 77 static int ipaqlcd_ioctl(void *, u_long, caddr_t, int, struct proc *); 78 static paddr_t ipaqlcd_mmap(void *, off_t offset, int); 79 80 #if defined __mips__ || defined __sh__ || defined __arm__ 81 #define __BTOP(x) ((paddr_t)(x) >> PGSHIFT) 82 #define __PTOB(x) ((paddr_t)(x) << PGSHIFT) 83 #else 84 #error "define btop, ptob." 85 #endif 86 87 struct cfattach ipaqlcd_ca = { 88 sizeof(struct ipaqlcd_softc), ipaqlcd_match, ipaqlcd_attach 89 }; 90 91 struct hpcfb_accessops ipaqlcd_ha = { 92 ipaqlcd_ioctl, ipaqlcd_mmap 93 }; 94 static int console_flag = 0; 95 96 static int 97 ipaqlcd_match(parent, match, aux) 98 struct device *parent; 99 struct cfdata *match; 100 void *aux; 101 { 102 return (1); 103 } 104 105 void 106 ipaqlcd_attach(parent, self, aux) 107 struct device *parent; 108 struct device *self; 109 void *aux; 110 { 111 struct ipaqlcd_softc *sc = (struct ipaqlcd_softc*)self; 112 struct hpcfb_attach_args ha; 113 struct ipaq_softc *psc = (struct ipaq_softc *)parent; 114 115 sc->sc_iot = psc->sc_iot; 116 sc->sc_parent = (struct ipaq_softc *)parent; 117 118 ipaqlcd_init(sc); 119 ipaqlcd_fbinit(sc); 120 121 printf("\n"); 122 printf("%s: iPAQ internal LCD controller\n", sc->sc_dev.dv_xname); 123 124 DPRINTF(("framebuffer_baseaddr=%lx\n", (u_long)bootinfo->fb_addr)); 125 126 ha.ha_console = console_flag; 127 ha.ha_accessops = &ipaqlcd_ha; 128 ha.ha_accessctx = sc; 129 ha.ha_curfbconf = 0; 130 ha.ha_nfbconf = 1; 131 ha.ha_fbconflist = &sc->sc_fbconf; 132 ha.ha_curdspconf = 0; 133 ha.ha_ndspconf = 1; 134 ha.ha_dspconflist = &sc->sc_dspconf; 135 136 config_found(&sc->sc_dev, &ha, hpcfbprint); 137 } 138 139 void 140 ipaqlcd_init(sc) 141 struct ipaqlcd_softc *sc; 142 { 143 /* Initialization of Extended GPIO */ 144 sc->sc_parent->ipaq_egpio |= EGPIO_LCD_INIT; 145 bus_space_write_2(sc->sc_iot, sc->sc_parent->sc_egpioh, 146 0, sc->sc_parent->ipaq_egpio); 147 148 if (bus_space_map(sc->sc_iot, SALCD_BASE, SALCD_NPORTS, 149 0, &sc->sc_ioh)) 150 panic("ipaqlcd_init:Cannot map registers\n"); 151 152 (u_long)bootinfo->fb_addr = 153 bus_space_read_4(sc->sc_iot, sc->sc_ioh, SALCD_BA1); 154 155 /* 156 * Initialize LCD Control Register 0 - 3 157 * must initialize DMA Channel Base Address Register 158 * before enabling LCD(LEN = 1) 159 */ 160 bus_space_write_4(sc->sc_iot, sc->sc_ioh, 161 SALCD_CR1, IPAQ_LCCR1); 162 bus_space_write_4(sc->sc_iot, sc->sc_ioh, 163 SALCD_CR2, IPAQ_LCCR2); 164 bus_space_write_4(sc->sc_iot, sc->sc_ioh, 165 SALCD_CR3, IPAQ_LCCR3); 166 bus_space_write_4(sc->sc_iot, sc->sc_ioh, 167 SALCD_CR0, IPAQ_LCCR0); 168 169 DPRINTF(("\n" 170 "DMA_BASE= %08x : DMA_CUR = %08x \n" 171 "LCCR0 = %08x : LCCR1 = %08x \n" 172 "LCCR2 = %08x : LCCR3 = %08x", 173 bus_space_read_4(sc->sc_iot, sc->sc_ioh, SALCD_BA1), 174 bus_space_read_4(sc->sc_iot, sc->sc_ioh, SALCD_CA1), 175 bus_space_read_4(sc->sc_iot, sc->sc_ioh, SALCD_CR0), 176 bus_space_read_4(sc->sc_iot, sc->sc_ioh, SALCD_CR1), 177 bus_space_read_4(sc->sc_iot, sc->sc_ioh, SALCD_CR2), 178 bus_space_read_4(sc->sc_iot, sc->sc_ioh, SALCD_CR3))); 179 180 } 181 182 int 183 ipaqlcd_fbinit(sc) 184 struct ipaqlcd_softc *sc; 185 { 186 struct hpcfb_fbconf *fb; 187 188 fb = &sc->sc_fbconf; 189 190 /* Initialize fb */ 191 memset(fb, 0, sizeof(*fb)); 192 193 fb->hf_conf_index = 0; /* configuration index */ 194 fb->hf_nconfs = 1; 195 strcpy(fb->hf_name, "built-in video"); 196 strcpy(fb->hf_conf_name, "LCD"); 197 /* configuration name */ 198 fb->hf_height = bootinfo->fb_height; 199 fb->hf_width = bootinfo->fb_width; 200 201 if (bus_space_map(sc->sc_iot, (bus_addr_t)bootinfo->fb_addr, 202 bootinfo->fb_height * bootinfo->fb_line_bytes, 203 0, &fb->hf_baseaddr)) { 204 printf("unable to map framebuffer\n"); 205 return (-1); 206 } 207 208 fb->hf_offset = (u_long)bootinfo->fb_addr - 209 __PTOB(__BTOP(bootinfo->fb_addr)); 210 /* frame buffer start offset */ 211 fb->hf_bytes_per_line = bootinfo->fb_line_bytes; 212 fb->hf_nplanes = 1; 213 fb->hf_bytes_per_plane = bootinfo->fb_height * 214 bootinfo->fb_line_bytes; 215 216 fb->hf_access_flags |= HPCFB_ACCESS_BYTE; 217 fb->hf_access_flags |= HPCFB_ACCESS_WORD; 218 fb->hf_access_flags |= HPCFB_ACCESS_DWORD; 219 220 switch (bootinfo->fb_type) { 221 /* 222 * gray scale 223 */ 224 case BIFB_D2_M2L_3: 225 case BIFB_D2_M2L_3x2: 226 fb->hf_access_flags |= HPCFB_ACCESS_REVERSE; 227 case BIFB_D2_M2L_0: 228 case BIFB_D2_M2L_0x2: 229 fb->hf_class = HPCFB_CLASS_GRAYSCALE; 230 break; 231 case BIFB_D4_M2L_F: 232 case BIFB_D4_M2L_Fx2: 233 fb->hf_access_flags |= HPCFB_ACCESS_REVERSE; 234 case BIFB_D4_M2L_0: 235 case BIFB_D4_M2L_0x2: 236 fb->hf_class = HPCFB_CLASS_GRAYSCALE; 237 break; 238 /* 239 * indexed color 240 */ 241 case BIFB_D8_FF: 242 case BIFB_D8_00: 243 fb->hf_offset = 0x200; 244 break; 245 /* 246 * RGB color 247 */ 248 case BIFB_D16_FFFF: 249 case BIFB_D16_0000: 250 fb->hf_class = HPCFB_CLASS_RGBCOLOR; 251 fb->hf_access_flags |= HPCFB_ACCESS_STATIC; 252 fb->hf_order_flags = HPCFB_REVORDER_BYTE; 253 fb->hf_pack_width = 16; 254 fb->hf_pixels_per_pack = 1; 255 fb->hf_pixel_width = 16; 256 257 fb->hf_class_data_length = sizeof(struct hf_rgb_tag); 258 fb->hf_u.hf_rgb.hf_flags = 0; 259 /* reserved for future use */ 260 fb->hf_u.hf_rgb.hf_red_width = 5; 261 fb->hf_u.hf_rgb.hf_red_shift = 11; 262 fb->hf_u.hf_rgb.hf_green_width = 6; 263 fb->hf_u.hf_rgb.hf_green_shift = 5; 264 fb->hf_u.hf_rgb.hf_blue_width = 5; 265 fb->hf_u.hf_rgb.hf_blue_shift = 0; 266 fb->hf_u.hf_rgb.hf_alpha_width = 0; 267 fb->hf_u.hf_rgb.hf_alpha_shift = 0; 268 break; 269 default : 270 printf("unknown type (=%d).\n", bootinfo->fb_type); 271 return (-1); 272 break; 273 } 274 275 return(0); 276 } 277 278 int 279 ipaqlcd_ioctl(v, cmd, data, flag, p) 280 void *v; 281 u_long cmd; 282 caddr_t data; 283 int flag; 284 struct proc *p; 285 { 286 struct ipaqlcd_softc *sc = (struct ipaqlcd_softc *)v; 287 struct hpcfb_fbconf *fbconf; 288 struct hpcfb_dspconf *dspconf; 289 struct wsdisplay_cmap *cmap; 290 struct wsdisplay_param *dispparam; 291 292 switch (cmd) { 293 case WSDISPLAYIO_GETCMAP: 294 cmap = (struct wsdisplay_cmap*)data; 295 296 if (sc->sc_fbconf.hf_class != HPCFB_CLASS_INDEXCOLOR || 297 sc->sc_fbconf.hf_pack_width != 8 || 298 256 <= cmap->index || 299 256 < (cmap->index + cmap->count)) 300 return (EINVAL); 301 return (0); 302 case WSDISPLAYIO_PUTCMAP: 303 return (EINVAL); 304 case WSDISPLAYIO_GETPARAM: 305 dispparam = (struct wsdisplay_param*)data; 306 switch (dispparam->param) { 307 case WSDISPLAYIO_PARAM_BACKLIGHT: 308 DPRINTF(("ipaqlcd_ioctl: GETPARAM:BACKLIGHT\n")); 309 return (EINVAL); 310 case WSDISPLAYIO_PARAM_CONTRAST: 311 DPRINTF(("ipaqlcd_ioctl: GETPARAM:CONTRAST\n")); 312 return (EINVAL); 313 case WSDISPLAYIO_PARAM_BRIGHTNESS: 314 DPRINTF(("ipaqlcd_ioctl: GETPARAM:BRIGHTNESS\n")); 315 return (EINVAL); 316 default: 317 return (EINVAL); 318 } 319 return (0); 320 case WSDISPLAYIO_SETPARAM: 321 dispparam = (struct wsdisplay_param*)data; 322 switch (dispparam->param) { 323 case WSDISPLAYIO_PARAM_BACKLIGHT: 324 DPRINTF(("ipaqlcd_ioctl: GETPARAM:BACKLIGHT\n")); 325 return (EINVAL); 326 case WSDISPLAYIO_PARAM_CONTRAST: 327 DPRINTF(("ipaqlcd_ioctl: GETPARAM:CONTRAST\n")); 328 return (EINVAL); 329 case WSDISPLAYIO_PARAM_BRIGHTNESS: 330 DPRINTF(("ipaqlcd_ioctl: GETPARAM:BRIGHTNESS\n")); 331 return (EINVAL); 332 default: 333 return (EINVAL); 334 } 335 return (0); 336 337 case HPCFBIO_GCONF: 338 fbconf = (struct hpcfb_fbconf *)data; 339 if (fbconf->hf_conf_index != 0 && 340 fbconf->hf_conf_index != HPCFB_CURRENT_CONFIG) { 341 return (EINVAL); 342 } 343 *fbconf = sc->sc_fbconf; /* structure assignment */ 344 return (0); 345 case HPCFBIO_SCONF: 346 fbconf = (struct hpcfb_fbconf *)data; 347 if (fbconf->hf_conf_index != 0 && 348 fbconf->hf_conf_index != HPCFB_CURRENT_CONFIG) { 349 return (EINVAL); 350 } 351 /* 352 * nothing to do because we have only one configration 353 */ 354 return (0); 355 case HPCFBIO_GDSPCONF: 356 dspconf = (struct hpcfb_dspconf *)data; 357 if ((dspconf->hd_unit_index != 0 && 358 dspconf->hd_unit_index != HPCFB_CURRENT_UNIT) || 359 (dspconf->hd_conf_index != 0 && 360 dspconf->hd_conf_index != HPCFB_CURRENT_CONFIG)) { 361 return (EINVAL); 362 } 363 *dspconf = sc->sc_dspconf; /* structure assignment */ 364 return (0); 365 case HPCFBIO_SDSPCONF: 366 dspconf = (struct hpcfb_dspconf *)data; 367 if ((dspconf->hd_unit_index != 0 && 368 dspconf->hd_unit_index != HPCFB_CURRENT_UNIT) || 369 (dspconf->hd_conf_index != 0 && 370 dspconf->hd_conf_index != HPCFB_CURRENT_CONFIG)) { 371 return (EINVAL); 372 } 373 /* 374 * nothing to do 375 * because we have only one unit and one configration 376 */ 377 return (0); 378 379 case HPCFBIO_GOP: 380 case HPCFBIO_SOP: 381 return (EINVAL); 382 } 383 return (EPASSTHROUGH); 384 } 385 386 paddr_t 387 ipaqlcd_mmap(ctx, offset, prot) 388 void *ctx; 389 off_t offset; 390 int prot; 391 { 392 struct ipaqlcd_softc *sc = (struct ipaqlcd_softc *)ctx; 393 394 if (offset < 0 || 395 (sc->sc_fbconf.hf_bytes_per_plane + 396 sc->sc_fbconf.hf_offset) < offset) 397 return -1; 398 399 return __BTOP((u_long)bootinfo->fb_addr + offset); 400 } 401