1 /* $NetBSD: netwalker_lcd.c,v 1.5 2015/12/21 04:26:29 hkenken Exp $ */ 2 3 /*- 4 * Copyright (c) 2011, 2012 Genetec corp. All rights reserved. 5 * Written by Hashimoto Kenichi for Genetec corp. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 17 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 18 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 19 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 20 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 24 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 26 * POSSIBILITY OF SUCH DAMAGE. 27 */ 28 29 #include <sys/cdefs.h> 30 __KERNEL_RCSID(0, "$NetBSD: netwalker_lcd.c,v 1.5 2015/12/21 04:26:29 hkenken Exp $"); 31 32 #include "opt_imx51_ipuv3.h" 33 #include "opt_netwalker_lcd.h" 34 35 #include "wsdisplay.h" 36 #include "ioconf.h" 37 #include "netwalker_backlight.h" 38 39 #include <sys/param.h> 40 #include <sys/device.h> 41 42 #include <sys/bus.h> 43 #include <arm/imx/imx51var.h> 44 #include <arm/imx/imx51reg.h> 45 #include <arm/imx/imx51_ipuv3var.h> 46 #include <arm/imx/imx51_ipuv3reg.h> 47 #include <arm/imx/imxgpiovar.h> 48 49 #include <evbarm/netwalker/netwalker_backlightvar.h> 50 51 int lcd_match(device_t, cfdata_t, void *); 52 void lcd_attach(device_t, device_t, void *); 53 54 #if NWSDISPLAY == 0 55 56 #ifdef LCD_DEBUG 57 static void draw_test_pattern(struct imx51_ipuv3_softc *, 58 struct imx51_ipuv3_screen *); 59 #endif 60 61 /* 62 * Interface to LCD framebuffer without wscons 63 */ 64 extern struct cfdriver ipu_cd; 65 66 dev_type_open(lcdopen); 67 dev_type_close(lcdclose); 68 dev_type_ioctl(lcdioctl); 69 dev_type_mmap(lcdmmap); 70 const struct cdevsw ipu_cdevsw = { 71 .d_open = lcdopen, 72 .d_close = lcdclose, 73 .d_read = noread, 74 .d_write = nowrite, 75 .d_ioctl = lcdioctl, 76 .d_stop = nostop, 77 .d_tty = notty, 78 .d_poll = nopoll, 79 .d_mmap = lcdmmap, 80 .d_kqfilter = nokqfilter, 81 .d_discard = nodiscard, 82 .d_flag = D_TTY 83 }; 84 85 #endif 86 87 CFATTACH_DECL_NEW(lcd_netwalker, sizeof (struct imx51_ipuv3_softc), 88 lcd_match, lcd_attach, NULL, NULL); 89 90 int 91 lcd_match( device_t parent, cfdata_t cf, void *aux ) 92 { 93 return 1; 94 } 95 96 /* Sharp's LCD */ 97 static const struct lcd_panel_geometry sharp_panel = { 98 .depth = 16, 99 100 .panel_width = 1024, /* Width */ 101 .panel_height = 600, /* Height */ 102 103 .pixel_clk = 30076000, 104 105 .hsync_width = 8, 106 .left = 20, 107 .right = 20, 108 109 .vsync_width = 4, 110 .upper = 2, 111 .lower = 2, 112 113 .panel_info = 0, 114 }; 115 116 void lcd_attach( device_t parent, device_t self, void *aux ) 117 { 118 struct imx51_ipuv3_softc *sc = device_private(self); 119 struct axi_attach_args *axia = aux; 120 bus_space_tag_t iot = axia->aa_iot; 121 122 sc->dev = self; 123 124 /* XXX move this to imx51_ipuv3.c */ 125 { 126 bus_space_handle_t mipi_ioh; 127 uint32_t reg; 128 129 if (bus_space_map(iot, 0x83fdc000, 0x1000, 0, &mipi_ioh)) 130 aprint_error_dev(self, "can't map MIPI HSC"); 131 else { 132 bus_space_write_4(iot, mipi_ioh, 0x000, 0xf00); 133 134 reg = bus_space_read_4(iot, mipi_ioh, 0x800); 135 bus_space_write_4(iot, mipi_ioh, 0x800, reg | 0x0ff); 136 137 reg = bus_space_read_4(iot, mipi_ioh, 0x800); 138 bus_space_write_4(iot, mipi_ioh, 0x800, reg | 0x10000); 139 } 140 } 141 142 /* LCD power on */ 143 gpio_set_direction(GPIO_NO(4, 9), GPIO_DIR_OUT); 144 gpio_set_direction(GPIO_NO(4, 10), GPIO_DIR_OUT); 145 gpio_set_direction(GPIO_NO(3, 3), GPIO_DIR_OUT); 146 147 gpio_data_write(GPIO_NO(3, 3), 1); 148 gpio_data_write(GPIO_NO(4, 9), 1); 149 delay(180 * 1000); 150 gpio_data_write(GPIO_NO(4, 10), 1); 151 152 gpio_set_direction(GPIO_NO(2, 13), GPIO_DIR_OUT); 153 gpio_data_write(GPIO_NO(2, 13), 1); 154 155 imx51_ipuv3_attach_sub(sc, aux, &sharp_panel); 156 157 #if NWSDISPLAY == 0 158 struct imx51_ipuv3_screen *screen; 159 int error; 160 161 error = imx51_ipuv3_new_screen(sc, &screen); 162 #ifdef LCD_DEBUG 163 draw_test_pattern(sc, screen); 164 #endif 165 if (error == 0) { 166 sc->active = screen; 167 imx51_ipuv3_start_dma(sc, screen); 168 } 169 #endif 170 } 171 172 #if NWSDISPLAY == 0 173 174 int 175 lcdopen(dev_t dev, int oflags, int devtype, struct lwp *l) 176 { 177 return 0; 178 } 179 180 int 181 lcdclose(dev_t dev, int fflag, int devtype, struct lwp *l) 182 { 183 return 0; 184 } 185 186 paddr_t 187 lcdmmap(dev_t dev, off_t offset, int size) 188 { 189 struct imx51_ipuv3_softc *sc = 190 device_lookup_private(&ipu_cd, minor(dev)); 191 struct imx51_ipuv3_screen *scr = sc->active; 192 193 return bus_dmamem_mmap(sc->dma_tag, scr->segs, scr->nsegs, 194 offset, 0, BUS_DMA_WAITOK|BUS_DMA_COHERENT); 195 } 196 197 int 198 lcdioctl(dev_t dev, u_long cmd, void *data, 199 int fflag, struct lwp *l) 200 { 201 return EOPNOTSUPP; 202 } 203 204 #ifdef LCD_DEBUG 205 static void 206 draw_test_pattern(struct imx51_ipuv3_softc *sc, 207 struct imx51_ipuv3_screen *scr) 208 { 209 int x, y; 210 uint16_t color, *line; 211 char *buf = (char *)(scr->buf_va); 212 213 printf("%s: buf_va %p, size 0x%x\n", __func__, buf, 214 (uint)scr->buf_size); 215 printf("%s: panel %d x %d\n", __func__, 216 sc->geometry->panel_width, 217 sc->geometry->panel_height); 218 #define rgb(r,g,b) (((r)<<11) | ((g)<<5) | (b)) 219 220 for (y=0; y < sc->geometry->panel_height; ++y) { 221 line = (uint16_t *)(buf + scr->stride * y); 222 223 for (x=0; x < sc->geometry->panel_width; ++x) { 224 switch (((x/30) + (y/10)) % 8) { 225 default: 226 case 0: color = rgb(0x00, 0x00, 0x00); break; 227 case 1: color = rgb(0x00, 0x00, 0x1f); break; 228 case 2: color = rgb(0x00, 0x3f, 0x00); break; 229 case 3: color = rgb(0x00, 0x3f, 0x1f); break; 230 case 4: color = rgb(0x1f, 0x00, 0x00); break; 231 case 5: color = rgb(0x1f, 0x00, 0x1f); break; 232 case 6: color = rgb(0x1f, 0x3f, 0x00); break; 233 case 7: color = rgb(0x1f, 0x3f, 0x1f); break; 234 } 235 236 line[x] = color; 237 } 238 } 239 240 for (x=0; x < MIN(sc->geometry->panel_height, 241 sc->geometry->panel_width); ++x) { 242 line = (uint16_t *)(buf + scr->stride * x); 243 line[x] = rgb(0x1f, 0x3f, 0x1f); 244 } 245 } 246 #endif 247 248 #endif /* NWSDISPLAY == 0 */ 249 250 251