1 /*        $NetBSD: mq200.c,v 1.36 2022/05/28 15:57:18 andvar Exp $    */
2 
3 /*-
4  * Copyright (c) 2000, 2001 TAKEMURA Shin
5  * All rights reserved.
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  * 3. The name of the author may not be used to endorse or promote products
16  *    derived from this software without specific prior written permission.
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
19  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
22  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28  * SUCH DAMAGE.
29  *
30  */
31 
32 #include <sys/cdefs.h>
33 __KERNEL_RCSID(0, "$NetBSD: mq200.c,v 1.36 2022/05/28 15:57:18 andvar Exp $");
34 
35 #include <sys/param.h>
36 #include <sys/bus.h>
37 #include <sys/device.h>
38 #include <sys/kernel.h>
39 #include <sys/systm.h>
40 #include <sys/reboot.h>
41 
42 #include <uvm/uvm_extern.h>
43 
44 #include <dev/wscons/wsconsio.h>
45 
46 #include <mips/locore.h>
47 
48 #include <machine/bootinfo.h>
49 #include <machine/autoconf.h>
50 #include <machine/config_hook.h>
51 #include <machine/platid.h>
52 #include <machine/platid_mask.h>
53 
54 #include "opt_mq200.h"
55 #include <hpcmips/dev/mq200reg.h>
56 #include <hpcmips/dev/mq200var.h>
57 #include <hpcmips/dev/mq200priv.h>
58 
59 #include "bivideo.h"
60 #if NBIVIDEO > 0
61 #include <dev/hpc/bivideovar.h>
62 #endif
63 
64 /*
65  * function prototypes
66  */
67 static void         mq200_power(int, void *);
68 static int          mq200_hardpower(void *, int, long, void *);
69 static int          mq200_fbinit(struct hpcfb_fbconf *);
70 static int          mq200_ioctl(void *, u_long, void *, int, struct lwp *);
71 static paddr_t      mq200_mmap(void *, off_t offset, int);
72 static void         mq200_update_powerstate(struct mq200_softc *, int);
73 void      mq200_init_backlight(struct mq200_softc *, int);
74 void      mq200_init_brightness(struct mq200_softc *, int);
75 void      mq200_init_contrast(struct mq200_softc *, int);
76 void      mq200_set_brightness(struct mq200_softc *, int);
77 void      mq200_set_contrast(struct mq200_softc *, int);
78 
79 /*
80  * static variables
81  */
82 struct hpcfb_accessops mq200_ha = {
83           mq200_ioctl, mq200_mmap
84 };
85 
86 #ifdef MQ200_DEBUG
87 int mq200_debug = MQ200DEBUG_CONF;
88 #endif
89 
90 int
mq200_probe(bus_space_tag_t iot,bus_space_handle_t ioh)91 mq200_probe(bus_space_tag_t iot, bus_space_handle_t ioh)
92 {
93           unsigned long regval;
94 
95 #if NBIVIDEO > 0
96           if (bivideo_dont_attach) /* some video driver already attached */
97                     return (0);
98 #endif /* NBIVIDEO > 0 */
99 
100           regval = bus_space_read_4(iot, ioh, MQ200_PC00R);
101           VPRINTF("probe: vendor id=%04lx product id=%04lx\n",
102               regval & 0xffff, (regval >> 16) & 0xffff);
103           if (regval != ((MQ200_PRODUCT_ID << 16) | MQ200_VENDOR_ID))
104                     return (0);
105 
106           return (1);
107 }
108 
109 void
mq200_attach(struct mq200_softc * sc)110 mq200_attach(struct mq200_softc *sc)
111 {
112           unsigned long regval;
113           struct hpcfb_attach_args ha;
114           int console = (bootinfo->bi_cnuse & BI_CNUSE_SERIAL) ? 0 : 1;
115 
116           printf(": ");
117           if (mq200_fbinit(&sc->sc_fbconf) != 0) {
118                     /* just return so that hpcfb will not be attached */
119                     return;
120           }
121 
122           sc->sc_fbconf.hf_baseaddr = (u_long)bootinfo->fb_addr;
123           sc->sc_fbconf.hf_offset       = (u_long)sc->sc_fbconf.hf_baseaddr -
124               MIPS_PHYS_TO_KSEG1(mips_ptob(mips_btop(sc->sc_baseaddr)));
125           DPRINTF("hf_baseaddr=%lx\n", sc->sc_fbconf.hf_baseaddr);
126           DPRINTF("hf_offset=%lx\n", sc->sc_fbconf.hf_offset);
127 
128           regval = mq200_read(sc, MQ200_PC08R);
129           printf("MQ200 Rev.%02lx video controller", regval & 0xff);
130           if (console) {
131                     printf(", console");
132           }
133           printf("\n");
134         printf("%s: framebuffer address: 0x%08lx\n",
135               device_xname(sc->sc_dev), (u_long)bootinfo->fb_addr);
136 
137           /*
138            * setup registers
139            */
140           sc->sc_flags = 0;
141           sc->sc_baseclock = 12288;     /* 12.288 MHz */
142 #ifdef MQ200_DEBUG
143           if (bootverbose) {
144                     /* dump current setting       */
145                     mq200_dump_all(sc);
146                     mq200_dump_pll(sc);
147           }
148 #endif
149           mq200_setup_regctx(sc);
150           mq200_mdsetup(sc);
151           if (sc->sc_md) {
152                     int mode;
153 
154                     switch (sc->sc_fbconf.hf_pixel_width) {
155                     case  1:  mode = MQ200_GCC_1BPP;                  break;
156                     case  2:  mode = MQ200_GCC_2BPP;                  break;
157                     case  4:  mode = MQ200_GCC_4BPP;                  break;
158                     case  8:  mode = MQ200_GCC_8BPP;                  break;
159                     case 16:  mode = MQ200_GCC_16BPP_DIRECT;          break;
160                     default:
161                               printf("%s: %dbpp isn't supported\n",
162                                   device_xname(sc->sc_dev), sc->sc_fbconf.hf_pixel_width);
163                               return;
164                     }
165 
166                     if (sc->sc_md->md_flags & MQ200_MD_HAVEFP) {
167                               sc->sc_flags |= MQ200_SC_GC2_ENABLE;    /* FP     */
168                     }
169 #if MQ200_USECRT
170                     if (sc->sc_md->md_flags & MQ200_MD_HAVECRT) {
171                               int i;
172                               sc->sc_flags |= MQ200_SC_GC1_ENABLE;    /* CRT    */
173                               for (i = 0; i < mq200_crt_nparams; i++) {
174                                         sc->sc_crt = &mq200_crt_params[i];
175                                         if (sc->sc_md->md_fp_width <=
176                                             mq200_crt_params[i].width &&
177                                             sc->sc_md->md_fp_height <=
178                                             mq200_crt_params[i].height)
179                                                   break;
180                               }
181                     }
182 #endif
183                     mq200_setup(sc);
184 
185                     if (sc->sc_flags & MQ200_SC_GC2_ENABLE) /* FP     */
186                               mq200_win_enable(sc, MQ200_GC2, mode,
187                                   sc->sc_fbconf.hf_baseaddr,
188                                   sc->sc_fbconf.hf_width, sc->sc_fbconf.hf_height,
189                                   sc->sc_fbconf.hf_bytes_per_plane);
190                     if (sc->sc_flags & MQ200_SC_GC1_ENABLE) /* CRT    */
191                               mq200_win_enable(sc, MQ200_GC1, mode,
192                                   sc->sc_fbconf.hf_baseaddr,
193                                   sc->sc_fbconf.hf_width, sc->sc_fbconf.hf_height,
194                                   sc->sc_fbconf.hf_bytes_per_plane);
195           }
196 #ifdef MQ200_DEBUG
197           if (sc->sc_md == NULL || bootverbose) {
198                     mq200_dump_pll(sc);
199           }
200 #endif
201 
202           /* Add a power hook to power saving */
203           sc->sc_mq200pwstate = MQ200_POWERSTATE_D0;
204           sc->sc_powerhook = powerhook_establish(device_xname(sc->sc_dev),
205               mq200_power, sc);
206           if (sc->sc_powerhook == NULL)
207                     printf("%s: WARNING: unable to establish power hook\n",
208                         device_xname(sc->sc_dev));
209 
210           /* Add a hard power hook to power saving */
211           sc->sc_hardpowerhook = config_hook(CONFIG_HOOK_PMEVENT,
212               CONFIG_HOOK_PMEVENT_HARDPOWER,
213               CONFIG_HOOK_SHARE,
214               mq200_hardpower, sc);
215           if (sc->sc_hardpowerhook == NULL)
216                     printf("%s: WARNING: unable to establish hard power hook\n",
217                         device_xname(sc->sc_dev));
218 
219           /* initialize backlight brightness and lcd contrast */
220           sc->sc_lcd_inited = 0;
221           mq200_init_brightness(sc, 1);
222           mq200_init_contrast(sc, 1);
223           mq200_init_backlight(sc, 1);
224 
225           if (console && hpcfb_cnattach(&sc->sc_fbconf) != 0) {
226                     panic("mq200_attach: can't init fb console");
227           }
228 
229           ha.ha_console = console;
230           ha.ha_accessops = &mq200_ha;
231           ha.ha_accessctx = sc;
232           ha.ha_curfbconf = 0;
233           ha.ha_nfbconf = 1;
234           ha.ha_fbconflist = &sc->sc_fbconf;
235           ha.ha_curdspconf = 0;
236           ha.ha_ndspconf = 1;
237           ha.ha_dspconflist = &sc->sc_dspconf;
238 
239           config_found(sc->sc_dev, &ha, hpcfbprint, CFARGS_NONE);
240 
241 #if NBIVIDEO > 0
242           /*
243            * bivideo is no longer need
244            */
245           bivideo_dont_attach = 1;
246 #endif /* NBIVIDEO > 0 */
247 }
248 
249 static void
mq200_update_powerstate(struct mq200_softc * sc,int updates)250 mq200_update_powerstate(struct mq200_softc *sc, int updates)
251 {
252 
253           if (updates & PWRSTAT_LCD)
254                     config_hook_call(CONFIG_HOOK_POWERCONTROL,
255                         CONFIG_HOOK_POWERCONTROL_LCD,
256                         (void*)!(sc->sc_powerstate &
257                               (PWRSTAT_VIDEOOFF|PWRSTAT_SUSPEND)));
258 
259           if (updates & PWRSTAT_BACKLIGHT)
260                     config_hook_call(CONFIG_HOOK_POWERCONTROL,
261                         CONFIG_HOOK_POWERCONTROL_LCDLIGHT,
262                         (void*)(!(sc->sc_powerstate &
263                               (PWRSTAT_VIDEOOFF|PWRSTAT_SUSPEND)) &&
264                               (sc->sc_powerstate & PWRSTAT_BACKLIGHT)));
265 }
266 
267 static void
mq200_power(int why,void * arg)268 mq200_power(int why, void *arg)
269 {
270           struct mq200_softc *sc = arg;
271 
272           switch (why) {
273           case PWR_SUSPEND:
274                     sc->sc_powerstate |= PWRSTAT_SUSPEND;
275                     mq200_update_powerstate(sc, PWRSTAT_ALL);
276                     break;
277           case PWR_STANDBY:
278                     sc->sc_powerstate |= PWRSTAT_SUSPEND;
279                     mq200_update_powerstate(sc, PWRSTAT_ALL);
280                     break;
281           case PWR_RESUME:
282                     sc->sc_powerstate &= ~PWRSTAT_SUSPEND;
283                     mq200_update_powerstate(sc, PWRSTAT_ALL);
284                     break;
285           }
286 }
287 
288 static int
mq200_hardpower(void * ctx,int type,long id,void * msg)289 mq200_hardpower(void *ctx, int type, long id, void *msg)
290 {
291           struct mq200_softc *sc = ctx;
292           int why = (int)msg;
293 
294           switch (why) {
295           case PWR_SUSPEND:
296                     sc->sc_mq200pwstate = MQ200_POWERSTATE_D2;
297                     break;
298           case PWR_STANDBY:
299                     sc->sc_mq200pwstate = MQ200_POWERSTATE_D3;
300                     break;
301           case PWR_RESUME:
302                     sc->sc_mq200pwstate = MQ200_POWERSTATE_D0;
303                     break;
304           }
305 
306           bus_space_write_4(sc->sc_iot, sc->sc_ioh,
307               MQ200_PMCSR, sc->sc_mq200pwstate);
308 
309           /*
310            * you should wait until the
311            * power state transit sequence will end.
312            */
313           {
314                     unsigned long tmp;
315                     do {
316                               tmp = bus_space_read_4(sc->sc_iot, sc->sc_ioh,
317                                   MQ200_PMCSR);
318                     } while ((tmp & 0x3) != (sc->sc_mq200pwstate & 0x3));
319                     delay(100000); /* XXX */
320           }
321 
322           return (0);
323 }
324 
325 
326 static int
mq200_fbinit(struct hpcfb_fbconf * fb)327 mq200_fbinit(struct hpcfb_fbconf *fb)
328 {
329 
330           /*
331            * get fb settings from bootinfo
332            */
333           if (bootinfo == NULL ||
334               bootinfo->fb_addr == 0 ||
335               bootinfo->fb_line_bytes == 0 ||
336               bootinfo->fb_width == 0 ||
337               bootinfo->fb_height == 0) {
338                     printf("no frame buffer information.\n");
339                     return (-1);
340           }
341 
342           /* zero fill */
343           memset(fb, 0, sizeof(*fb));
344 
345           fb->hf_conf_index   = 0;      /* configuration index                  */
346           fb->hf_nconfs                 = 1;      /* how many configurations    */
347           strcpy(fb->hf_name, "built-in video");
348                                                   /* frame buffer name                    */
349           strcpy(fb->hf_conf_name, "default");
350                                                   /* configuration name                   */
351           fb->hf_height                 = bootinfo->fb_height;
352           fb->hf_width                  = bootinfo->fb_width;
353           fb->hf_baseaddr               = mips_ptob(mips_btop(bootinfo->fb_addr));
354           fb->hf_offset                 = (u_long)bootinfo->fb_addr - fb->hf_baseaddr;
355                                                   /* frame buffer start offset            */
356           fb->hf_bytes_per_line         = bootinfo->fb_line_bytes;
357           fb->hf_nplanes                = 1;
358           fb->hf_bytes_per_plane        = bootinfo->fb_height *
359               bootinfo->fb_line_bytes;
360 
361           fb->hf_access_flags |= HPCFB_ACCESS_BYTE;
362           fb->hf_access_flags |= HPCFB_ACCESS_WORD;
363           fb->hf_access_flags |= HPCFB_ACCESS_DWORD;
364 
365           switch (bootinfo->fb_type) {
366                     /*
367                      * monochrome
368                      */
369           case BIFB_D1_M2L_1:
370                     fb->hf_access_flags |= HPCFB_ACCESS_REVERSE;
371                     /* fall through */
372           case BIFB_D1_M2L_0:
373                     fb->hf_class = HPCFB_CLASS_GRAYSCALE;
374                     fb->hf_access_flags |= HPCFB_ACCESS_STATIC;
375                     fb->hf_pack_width = 8;
376                     fb->hf_pixels_per_pack = 8;
377                     fb->hf_pixel_width = 1;
378                     fb->hf_class_data_length = sizeof(struct hf_gray_tag);
379                     fb->hf_u.hf_gray.hf_flags = 0;          /* reserved for future use */
380                     break;
381 
382                     /*
383                      * gray scale
384                      */
385           case BIFB_D2_M2L_3:
386           case BIFB_D2_M2L_3x2:
387                     fb->hf_access_flags |= HPCFB_ACCESS_REVERSE;
388                     /* fall through */
389           case BIFB_D2_M2L_0:
390           case BIFB_D2_M2L_0x2:
391                     fb->hf_class = HPCFB_CLASS_GRAYSCALE;
392                     fb->hf_access_flags |= HPCFB_ACCESS_STATIC;
393                     fb->hf_pack_width = 8;
394                     fb->hf_pixels_per_pack = 4;
395                     fb->hf_pixel_width = 2;
396                     fb->hf_class_data_length = sizeof(struct hf_gray_tag);
397                     fb->hf_u.hf_gray.hf_flags = 0;          /* reserved for future use */
398                     break;
399 
400           case BIFB_D4_M2L_F:
401           case BIFB_D4_M2L_Fx2:
402                     fb->hf_access_flags |= HPCFB_ACCESS_REVERSE;
403                     /* fall through */
404           case BIFB_D4_M2L_0:
405           case BIFB_D4_M2L_0x2:
406                     fb->hf_class = HPCFB_CLASS_GRAYSCALE;
407                     fb->hf_access_flags |= HPCFB_ACCESS_STATIC;
408                     fb->hf_pack_width = 8;
409                     fb->hf_pixels_per_pack = 2;
410                     fb->hf_pixel_width = 4;
411                     fb->hf_class_data_length = sizeof(struct hf_gray_tag);
412                     fb->hf_u.hf_gray.hf_flags = 0;          /* reserved for future use */
413                     break;
414 
415                     /*
416                      * indexed color
417                      */
418           case BIFB_D8_FF:
419                     fb->hf_access_flags |= HPCFB_ACCESS_REVERSE;
420                     /* fall through */
421           case BIFB_D8_00:
422                     fb->hf_class = HPCFB_CLASS_INDEXCOLOR;
423                     fb->hf_access_flags |= HPCFB_ACCESS_STATIC;
424                     fb->hf_pack_width = 8;
425                     fb->hf_pixels_per_pack = 1;
426                     fb->hf_pixel_width = 8;
427                     fb->hf_class_data_length = sizeof(struct hf_indexed_tag);
428                     fb->hf_u.hf_indexed.hf_flags = 0; /* reserved for future use */
429                     break;
430 
431                     /*
432                      * RGB color
433                      */
434           case BIFB_D16_FFFF:
435                     fb->hf_access_flags |= HPCFB_ACCESS_REVERSE;
436                     /* fall through */
437           case BIFB_D16_0000:
438                     fb->hf_class = HPCFB_CLASS_RGBCOLOR;
439                     fb->hf_access_flags |= HPCFB_ACCESS_STATIC;
440                     fb->hf_order_flags = HPCFB_REVORDER_BYTE;
441                     fb->hf_pack_width = 16;
442                     fb->hf_pixels_per_pack = 1;
443                     fb->hf_pixel_width = 16;
444 
445                     fb->hf_class_data_length = sizeof(struct hf_rgb_tag);
446                     fb->hf_u.hf_rgb.hf_flags = 0; /* reserved for future use */
447 
448                     fb->hf_u.hf_rgb.hf_red_width = 5;
449                     fb->hf_u.hf_rgb.hf_red_shift = 11;
450                     fb->hf_u.hf_rgb.hf_green_width = 6;
451                     fb->hf_u.hf_rgb.hf_green_shift = 5;
452                     fb->hf_u.hf_rgb.hf_blue_width = 5;
453                     fb->hf_u.hf_rgb.hf_blue_shift = 0;
454                     fb->hf_u.hf_rgb.hf_alpha_width = 0;
455                     fb->hf_u.hf_rgb.hf_alpha_shift = 0;
456                     break;
457 
458           default:
459                     printf("unknown type (=%d).\n", bootinfo->fb_type);
460                     return (-1);
461                     break;
462           }
463 
464           return (0); /* no error */
465 }
466 
467 int
mq200_ioctl(void * v,u_long cmd,void * data,int flag,struct lwp * l)468 mq200_ioctl(void *v, u_long cmd, void *data, int flag, struct lwp *l)
469 {
470           struct mq200_softc *sc = (struct mq200_softc *)v;
471           struct hpcfb_fbconf *fbconf;
472           struct hpcfb_dspconf *dspconf;
473           struct wsdisplay_cmap *cmap;
474           struct wsdisplay_param *dispparam;
475 
476           switch (cmd) {
477           case WSDISPLAYIO_GETCMAP:
478                     cmap = (struct wsdisplay_cmap *)data;
479 
480                     if (sc->sc_fbconf.hf_class != HPCFB_CLASS_INDEXCOLOR ||
481                         sc->sc_fbconf.hf_pack_width != 8 ||
482                         256 <= cmap->index ||
483                         256 - cmap->index < cmap->count)
484                               return (EINVAL);
485 
486                     /*
487                      * This driver can't get color map.
488                      */
489                     return (EINVAL);
490 
491           case WSDISPLAYIO_PUTCMAP:
492                     /*
493                      * This driver can't set color map.
494                      */
495                     return (EINVAL);
496 
497           case WSDISPLAYIO_SVIDEO:
498                     if (*(int *)data == WSDISPLAYIO_VIDEO_OFF)
499                               sc->sc_powerstate |= PWRSTAT_VIDEOOFF;
500                     else
501                               sc->sc_powerstate &= ~PWRSTAT_VIDEOOFF;
502                     mq200_update_powerstate(sc, PWRSTAT_ALL);
503                     return 0;
504 
505           case WSDISPLAYIO_GVIDEO:
506                     *(int *)data = (sc->sc_powerstate&PWRSTAT_VIDEOOFF) ?
507                         WSDISPLAYIO_VIDEO_OFF:WSDISPLAYIO_VIDEO_ON;
508                     return 0;
509 
510           case WSDISPLAYIO_GETPARAM:
511                     dispparam = (struct wsdisplay_param*)data;
512                     switch (dispparam->param) {
513                     case WSDISPLAYIO_PARAM_BACKLIGHT:
514                               VPRINTF("ioctl: GET:BACKLIGHT\n");
515                               mq200_init_brightness(sc, 0);
516                               mq200_init_backlight(sc, 0);
517                               VPRINTF("ioctl: GET:(real)BACKLIGHT %d\n",
518                                   (sc->sc_powerstate&PWRSTAT_BACKLIGHT)? 1: 0);
519                               dispparam->min = 0;
520                               dispparam->max = 1;
521                               if (sc->sc_max_brightness > 0)
522                                         dispparam->curval = sc->sc_brightness > 0
523                                             ? 1: 0;
524                               else
525                                         dispparam->curval =
526                                             (sc->sc_powerstate&PWRSTAT_BACKLIGHT)
527                                             ? 1: 0;
528                               VPRINTF("ioctl: GET:BACKLIGHT:%d(%s)\n",
529                                   dispparam->curval,
530                                   sc->sc_max_brightness > 0? "brightness": "light");
531                               return 0;
532                               break;
533                     case WSDISPLAYIO_PARAM_CONTRAST:
534                               VPRINTF("ioctl: GET:CONTRAST\n");
535                               mq200_init_contrast(sc, 0);
536                               if (sc->sc_max_contrast > 0) {
537                                         dispparam->min = 0;
538                                         dispparam->max = sc->sc_max_contrast;
539                                         dispparam->curval = sc->sc_contrast;
540                                         VPRINTF("ioctl: GET:CONTRAST"
541                                             " max=%d, current=%d\n",
542                                             sc->sc_max_contrast, sc->sc_contrast);
543                                         return 0;
544                               } else {
545                                         VPRINTF("ioctl: GET:CONTRAST EINVAL\n");
546                                         return (EINVAL);
547                               }
548                               break;
549                     case WSDISPLAYIO_PARAM_BRIGHTNESS:
550                               VPRINTF("ioctl: GET:BRIGHTNESS\n");
551                               mq200_init_brightness(sc, 0);
552                               if (sc->sc_max_brightness > 0) {
553                                         dispparam->min = 0;
554                                         dispparam->max = sc->sc_max_brightness;
555                                         dispparam->curval = sc->sc_brightness;
556                                         VPRINTF("ioctl: GET:BRIGHTNESS"
557                                             " max=%d, current=%d\n",
558                                             sc->sc_max_brightness, sc->sc_brightness);
559                                         return 0;
560                               } else {
561                                         VPRINTF("ioctl: GET:BRIGHTNESS EINVAL\n");
562                                         return (EINVAL);
563                               }
564                               return (EINVAL);
565                     default:
566                               return (EINVAL);
567                     }
568                     return (0);
569 
570           case WSDISPLAYIO_SETPARAM:
571                     dispparam = (struct wsdisplay_param*)data;
572                     switch (dispparam->param) {
573                     case WSDISPLAYIO_PARAM_BACKLIGHT:
574                               VPRINTF("ioctl: SET:BACKLIGHT\n");
575                               if (dispparam->curval < 0 ||
576                                   1 < dispparam->curval)
577                                         return (EINVAL);
578                               mq200_init_brightness(sc, 0);
579                               VPRINTF("ioctl: SET:max brightness=%d\n",
580                                   sc->sc_max_brightness);
581                               if (sc->sc_max_brightness > 0) { /* dimmer */
582                                         if (dispparam->curval == 0){
583                                                   sc->sc_brightness_save =
584                                                       sc->sc_brightness;
585                                                   mq200_set_brightness(sc, 0); /* min */
586                                         } else {
587                                                   if (sc->sc_brightness_save == 0)
588                                                             sc->sc_brightness_save =
589                                                                 sc->sc_max_brightness;
590                                                   mq200_set_brightness(sc,
591                                                       sc->sc_brightness_save);
592                                         }
593                                         VPRINTF("ioctl: SET:BACKLIGHT:"
594                                             " brightness=%d\n", sc->sc_brightness);
595                               } else { /* off */
596                                         if (dispparam->curval == 0)
597                                                   sc->sc_powerstate &= ~PWRSTAT_BACKLIGHT;
598                                         else
599                                                   sc->sc_powerstate |= PWRSTAT_BACKLIGHT;
600                                         VPRINTF("ioctl: SET:BACKLIGHT:"
601                                             " powerstate %d\n",
602                                             (sc->sc_powerstate & PWRSTAT_BACKLIGHT)
603                                             ? 1 : 0);
604                                         mq200_update_powerstate(sc, PWRSTAT_BACKLIGHT);
605                                         VPRINTF("ioctl: SET:BACKLIGHT:%d\n",
606                                             (sc->sc_powerstate & PWRSTAT_BACKLIGHT)
607                                             ? 1 : 0);
608                               }
609                               return 0;
610                               break;
611                     case WSDISPLAYIO_PARAM_CONTRAST:
612                               VPRINTF("ioctl: SET:CONTRAST\n");
613                               mq200_init_contrast(sc, 0);
614                               if (dispparam->curval < 0 ||
615                                   sc->sc_max_contrast < dispparam->curval)
616                                         return (EINVAL);
617                               if (sc->sc_max_contrast > 0) {
618                                         int org = sc->sc_contrast;
619                                         mq200_set_contrast(sc, dispparam->curval);
620                                         VPRINTF("ioctl: SET:CONTRAST"
621                                             " org=%d, current=%d\n", org,
622                                             sc->sc_contrast);
623                                         VPRINTF("ioctl: SETPARAM:"
624                                             " CONTRAST org=%d, current=%d\n", org,
625                                             sc->sc_contrast);
626                                         return 0;
627                               } else {
628                                         VPRINTF("ioctl: SET:CONTRAST EINVAL\n");
629                                         return (EINVAL);
630                               }
631                               break;
632                     case WSDISPLAYIO_PARAM_BRIGHTNESS:
633                               VPRINTF("ioctl: SET:BRIGHTNESS\n");
634                               mq200_init_brightness(sc, 0);
635                               if (dispparam->curval < 0 ||
636                                   sc->sc_max_brightness < dispparam->curval)
637                                         return (EINVAL);
638                               if (sc->sc_max_brightness > 0) {
639                                         int org = sc->sc_brightness;
640                                         mq200_set_brightness(sc, dispparam->curval);
641                                         VPRINTF("ioctl: SET:BRIGHTNESS"
642                                             " org=%d, current=%d\n", org,
643                                             sc->sc_brightness);
644                                         return 0;
645                               } else {
646                                         VPRINTF("ioctl: SET:BRIGHTNESS EINVAL\n");
647                                         return (EINVAL);
648                               }
649                               break;
650                     default:
651                               return (EINVAL);
652                     }
653                     return (0);
654 
655           case HPCFBIO_GCONF:
656                     fbconf = (struct hpcfb_fbconf *)data;
657                     if (fbconf->hf_conf_index != 0 &&
658                         fbconf->hf_conf_index != HPCFB_CURRENT_CONFIG) {
659                               return (EINVAL);
660                     }
661                     *fbconf = sc->sc_fbconf;      /* structure assignment */
662                     return (0);
663           case HPCFBIO_SCONF:
664                     fbconf = (struct hpcfb_fbconf *)data;
665                     if (fbconf->hf_conf_index != 0 &&
666                         fbconf->hf_conf_index != HPCFB_CURRENT_CONFIG) {
667                               return (EINVAL);
668                     }
669                     /*
670                      * nothing to do because we have only one configuration
671                      */
672                     return (0);
673           case HPCFBIO_GDSPCONF:
674                     dspconf = (struct hpcfb_dspconf *)data;
675                     if ((dspconf->hd_unit_index != 0 &&
676                         dspconf->hd_unit_index != HPCFB_CURRENT_UNIT) ||
677                         (dspconf->hd_conf_index != 0 &&
678                               dspconf->hd_conf_index != HPCFB_CURRENT_CONFIG)) {
679                               return (EINVAL);
680                     }
681                     *dspconf = sc->sc_dspconf;    /* structure assignment */
682                     return (0);
683           case HPCFBIO_SDSPCONF:
684                     dspconf = (struct hpcfb_dspconf *)data;
685                     if ((dspconf->hd_unit_index != 0 &&
686                         dspconf->hd_unit_index != HPCFB_CURRENT_UNIT) ||
687                         (dspconf->hd_conf_index != 0 &&
688                               dspconf->hd_conf_index != HPCFB_CURRENT_CONFIG)) {
689                               return (EINVAL);
690                     }
691                     /*
692                      * nothing to do
693                      * because we have only one unit and one configuration
694                      */
695                     return (0);
696           case HPCFBIO_GOP:
697           case HPCFBIO_SOP:
698                     /*
699                      * currently not implemented...
700                      */
701                     return (EINVAL);
702           }
703 
704           return (EPASSTHROUGH);
705 }
706 
707 paddr_t
mq200_mmap(void * ctx,off_t offset,int prot)708 mq200_mmap(void *ctx, off_t offset, int prot)
709 {
710           struct mq200_softc *sc = (struct mq200_softc *)ctx;
711 
712           if (offset < 0 || MQ200_MAPSIZE <= offset)
713                     return -1;
714 
715           return mips_btop(sc->sc_baseaddr + offset);
716 }
717 
718 
719 void
mq200_init_backlight(struct mq200_softc * sc,int inattach)720 mq200_init_backlight(struct mq200_softc *sc, int inattach)
721 {
722           int val = -1;
723 
724           if (sc->sc_lcd_inited&BACKLIGHT_INITED)
725                     return;
726 
727           if (config_hook_call(CONFIG_HOOK_GET,
728               CONFIG_HOOK_POWER_LCDLIGHT, &val) != -1) {
729                     /* we can get real light state */
730                     VPRINTF("init_backlight: real backlight=%d\n", val);
731                     if (val == 0)
732                               sc->sc_powerstate &= ~PWRSTAT_BACKLIGHT;
733                     else
734                               sc->sc_powerstate |= PWRSTAT_BACKLIGHT;
735                     sc->sc_lcd_inited |= BACKLIGHT_INITED;
736           } else if (inattach) {
737                     /*
738                        we cannot get real light state in attach time
739                        because light device not yet attached.
740                        we will retry in !inattach.
741                        temporary assume light is on.
742                     */
743                     sc->sc_powerstate |= PWRSTAT_BACKLIGHT;
744           } else {
745                     /* we cannot get real light state, so work by myself state */
746                     sc->sc_lcd_inited |= BACKLIGHT_INITED;
747           }
748 }
749 
750 void
mq200_init_brightness(struct mq200_softc * sc,int inattach)751 mq200_init_brightness(struct mq200_softc *sc, int inattach)
752 {
753           int val = -1;
754 
755           if (sc->sc_lcd_inited&BRIGHTNESS_INITED)
756                     return;
757 
758           VPRINTF("init_brightness\n");
759           if (config_hook_call(CONFIG_HOOK_GET,
760               CONFIG_HOOK_BRIGHTNESS_MAX, &val) != -1) {
761                     /* we can get real brightness max */
762                     VPRINTF("init_brightness: real brightness max=%d\n", val);
763                     sc->sc_max_brightness = val;
764                     val = -1;
765                     if (config_hook_call(CONFIG_HOOK_GET,
766                         CONFIG_HOOK_BRIGHTNESS, &val) != -1) {
767                               /* we can get real brightness */
768                               VPRINTF("init_brightness: real brightness=%d\n", val);
769                               sc->sc_brightness_save = sc->sc_brightness = val;
770                     } else {
771                               sc->sc_brightness_save =
772                                   sc->sc_brightness = sc->sc_max_brightness;
773                     }
774                     sc->sc_lcd_inited |= BRIGHTNESS_INITED;
775           } else if (inattach) {
776                     /*
777                        we cannot get real brightness in attach time
778                        because brightness device not yet attached.
779                        we will retry in !inattach.
780                     */
781                     sc->sc_max_brightness = -1;
782                     sc->sc_brightness = -1;
783                     sc->sc_brightness_save = -1;
784           } else {
785                     /* we cannot get real brightness */
786                     sc->sc_lcd_inited |= BRIGHTNESS_INITED;
787           }
788 
789           return;
790 }
791 
792 
793 void
mq200_init_contrast(struct mq200_softc * sc,int inattach)794 mq200_init_contrast(struct mq200_softc *sc, int inattach)
795 {
796           int val = -1;
797 
798           if (sc->sc_lcd_inited&CONTRAST_INITED)
799                     return;
800 
801           VPRINTF("init_contrast\n");
802           if (config_hook_call(CONFIG_HOOK_GET,
803               CONFIG_HOOK_CONTRAST_MAX, &val) != -1) {
804                     /* we can get real contrast max */
805                     VPRINTF("init_contrast: real contrast max=%d\n", val);
806                     sc->sc_max_contrast = val;
807                     val = -1;
808                     if (config_hook_call(CONFIG_HOOK_GET,
809                         CONFIG_HOOK_CONTRAST, &val) != -1) {
810                               /* we can get real contrast */
811                               VPRINTF("init_contrast: real contrast=%d\n", val);
812                               sc->sc_contrast = val;
813                     } else {
814                               sc->sc_contrast = sc->sc_max_contrast;
815                     }
816                     sc->sc_lcd_inited |= CONTRAST_INITED;
817           } else if (inattach) {
818                     /*
819                        we cannot get real contrast in attach time
820                        because contrast device not yet attached.
821                        we will retry in !inattach.
822                     */
823                     sc->sc_max_contrast = -1;
824                     sc->sc_contrast = -1;
825           } else {
826                     /* we cannot get real contrast */
827                     sc->sc_lcd_inited |= CONTRAST_INITED;
828           }
829 
830           return;
831 }
832 
833 
834 void
mq200_set_brightness(struct mq200_softc * sc,int val)835 mq200_set_brightness(struct mq200_softc *sc, int val)
836 {
837           sc->sc_brightness = val;
838 
839           config_hook_call(CONFIG_HOOK_SET, CONFIG_HOOK_BRIGHTNESS, &val);
840           if (config_hook_call(CONFIG_HOOK_GET,
841               CONFIG_HOOK_BRIGHTNESS, &val) != -1) {
842                     sc->sc_brightness = val;
843           }
844 }
845 
846 void
mq200_set_contrast(struct mq200_softc * sc,int val)847 mq200_set_contrast(struct mq200_softc *sc, int val)
848 {
849           sc->sc_contrast = val;
850 
851           config_hook_call(CONFIG_HOOK_SET, CONFIG_HOOK_CONTRAST, &val);
852           if (config_hook_call(CONFIG_HOOK_GET,
853               CONFIG_HOOK_CONTRAST, &val) != -1) {
854                     sc->sc_contrast = val;
855           }
856 }
857