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