1*86c30724Sandvar /* $NetBSD: bivideo.c,v 1.37 2022/05/28 10:36:23 andvar Exp $ */
2659f65e0Such
3659f65e0Such /*-
4edde743dSuch * Copyright (c) 1999-2001
5659f65e0Such * Shin Takemura and PocketBSD Project. All rights reserved.
6659f65e0Such *
7659f65e0Such * Redistribution and use in source and binary forms, with or without
8659f65e0Such * modification, are permitted provided that the following conditions
9659f65e0Such * are met:
10659f65e0Such * 1. Redistributions of source code must retain the above copyright
11659f65e0Such * notice, this list of conditions and the following disclaimer.
12659f65e0Such * 2. Redistributions in binary form must reproduce the above copyright
13659f65e0Such * notice, this list of conditions and the following disclaimer in the
14659f65e0Such * documentation and/or other materials provided with the distribution.
15659f65e0Such * 3. All advertising materials mentioning features or use of this software
16659f65e0Such * must display the following acknowledgement:
17659f65e0Such * This product includes software developed by the PocketBSD project
18659f65e0Such * and its contributors.
19659f65e0Such * 4. Neither the name of the project nor the names of its contributors
20659f65e0Such * may be used to endorse or promote products derived from this software
21659f65e0Such * without specific prior written permission.
22659f65e0Such *
23659f65e0Such * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
24659f65e0Such * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25659f65e0Such * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26659f65e0Such * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
27659f65e0Such * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28659f65e0Such * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29659f65e0Such * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30659f65e0Such * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31659f65e0Such * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32659f65e0Such * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33659f65e0Such * SUCH DAMAGE.
34659f65e0Such *
35659f65e0Such */
36b84f53efSlukem
37b84f53efSlukem #include <sys/cdefs.h>
38*86c30724Sandvar __KERNEL_RCSID(0, "$NetBSD: bivideo.c,v 1.37 2022/05/28 10:36:23 andvar Exp $");
39b84f53efSlukem
409eddf385Speter #ifdef _KERNEL_OPT
419eddf385Speter #include "opt_hpcfb.h"
429eddf385Speter #endif
43659f65e0Such
44659f65e0Such #include <sys/param.h>
45659f65e0Such #include <sys/systm.h>
46659f65e0Such #include <sys/device.h>
47659f65e0Such #include <sys/buf.h>
48659f65e0Such #include <sys/ioctl.h>
49659f65e0Such #include <sys/reboot.h>
50659f65e0Such
51a2a38285Sad #include <sys/bus.h>
52659f65e0Such #include <machine/autoconf.h>
53659f65e0Such #include <machine/bootinfo.h>
54659f65e0Such #include <machine/config_hook.h>
55659f65e0Such
56659f65e0Such #include <dev/wscons/wsconsio.h>
57659f65e0Such #include <dev/wscons/wsdisplayvar.h>
58659f65e0Such
59659f65e0Such #include <dev/rasops/rasops.h>
60659f65e0Such
61659f65e0Such #include <dev/hpc/hpcfbvar.h>
62659f65e0Such #include <dev/hpc/hpcfbio.h>
63659f65e0Such #include <dev/hpc/bivideovar.h>
64659f65e0Such #include <dev/hpc/hpccmapvar.h>
65659f65e0Such
669eddf385Speter #ifdef FBDEBUG
679eddf385Speter #define VPRINTF(arg) do { if (bootverbose) printf arg; } while (0)
689eddf385Speter #else
699eddf385Speter #define VPRINTF(arg) /* nothing */
709eddf385Speter #endif
71659f65e0Such
72659f65e0Such /*
73659f65e0Such * global variables
74659f65e0Such */
75659f65e0Such int bivideo_dont_attach = 0;
76659f65e0Such
77659f65e0Such /*
78659f65e0Such * function prototypes
79659f65e0Such */
80529e91fcScegger int bivideomatch(device_t, cfdata_t, void *);
81529e91fcScegger void bivideoattach(device_t, device_t, void *);
8253524e44Schristos int bivideo_ioctl(void *, u_long, void *, int, struct lwp *);
83edde743dSuch paddr_t bivideo_mmap(void *, off_t, int);
84659f65e0Such
85659f65e0Such struct bivideo_softc {
86659f65e0Such struct hpcfb_fbconf sc_fbconf;
87659f65e0Such struct hpcfb_dspconf sc_dspconf;
88659f65e0Such int sc_powerstate;
89659f65e0Such #define PWRSTAT_SUSPEND (1<<0)
9080214041Ssato #define PWRSTAT_VIDEOOFF (1<<1)
9180214041Ssato #define PWRSTAT_LCD (1<<2)
9280214041Ssato #define PWRSTAT_BACKLIGHT (1<<3)
93659f65e0Such #define PWRSTAT_ALL (0xffffffff)
946c5da9bdSsato int sc_lcd_inited;
956c5da9bdSsato #define BACKLIGHT_INITED (1<<0)
966c5da9bdSsato #define BRIGHTNESS_INITED (1<<1)
976c5da9bdSsato #define CONTRAST_INITED (1<<2)
98b8e5bc56Ssato int sc_brightness;
99b8e5bc56Ssato int sc_brightness_save;
100b8e5bc56Ssato int sc_max_brightness;
101b8e5bc56Ssato int sc_contrast;
102b8e5bc56Ssato int sc_max_contrast;
103b8e5bc56Ssato
104659f65e0Such };
105b8e5bc56Ssato
106edde743dSuch static int bivideo_init(struct hpcfb_fbconf *);
107edde743dSuch static void bivideo_power(int, void *);
108edde743dSuch static void bivideo_update_powerstate(struct bivideo_softc *, int);
109f928eeabStsutsui static bool bivideo_suspend(device_t, const pmf_qual_t *);
110f928eeabStsutsui static bool bivideo_resume(device_t, const pmf_qual_t *);
1116c5da9bdSsato void bivideo_init_backlight(struct bivideo_softc *, int);
1126c5da9bdSsato void bivideo_init_brightness(struct bivideo_softc *, int);
1136c5da9bdSsato void bivideo_init_contrast(struct bivideo_softc *, int);
114b8e5bc56Ssato void bivideo_set_brightness(struct bivideo_softc *, int);
115b8e5bc56Ssato void bivideo_set_contrast(struct bivideo_softc *, int);
116659f65e0Such
117edde743dSuch #if defined __mips__ || defined __sh__ || defined __arm__
118edde743dSuch #define __BTOP(x) ((paddr_t)(x) >> PGSHIFT)
119edde743dSuch #define __PTOB(x) ((paddr_t)(x) << PGSHIFT)
120edde743dSuch #else
121edde743dSuch #error "define btop, ptob."
122edde743dSuch #endif
123659f65e0Such
124659f65e0Such /*
125659f65e0Such * static variables
126659f65e0Such */
127cbab9cadSchs CFATTACH_DECL_NEW(bivideo, sizeof(struct bivideo_softc),
128c9b3657cSthorpej bivideomatch, bivideoattach, NULL, NULL);
1299d4a6407Sthorpej
130659f65e0Such struct hpcfb_accessops bivideo_ha = {
131659f65e0Such bivideo_ioctl, bivideo_mmap
132659f65e0Such };
133659f65e0Such
134659f65e0Such static int console_flag = 0;
135659f65e0Such static int attach_flag = 0;
136659f65e0Such
137659f65e0Such /*
138659f65e0Such * function bodies
139659f65e0Such */
140659f65e0Such int
bivideomatch(device_t parent,cfdata_t match,void * aux)141529e91fcScegger bivideomatch(device_t parent, cfdata_t match, void *aux)
142659f65e0Such {
143659f65e0Such struct mainbus_attach_args *ma = aux;
144659f65e0Such
145659f65e0Such if (bivideo_dont_attach ||
146d1ad2ac4Sthorpej strcmp(ma->ma_name, match->cf_name))
147659f65e0Such return 0;
148659f65e0Such
149659f65e0Such return (1);
150659f65e0Such }
151659f65e0Such
152659f65e0Such void
bivideoattach(device_t parent,device_t self,void * aux)153529e91fcScegger bivideoattach(device_t parent, device_t self, void *aux)
154659f65e0Such {
15592c7bba3Sthorpej struct bivideo_softc *sc = device_private(self);
156659f65e0Such struct hpcfb_attach_args ha;
157659f65e0Such
158659f65e0Such if (attach_flag) {
159659f65e0Such panic("%s(%d): bivideo attached twice", __FILE__, __LINE__);
160659f65e0Such }
161659f65e0Such attach_flag = 1;
162659f65e0Such
163659f65e0Such printf(": ");
164659f65e0Such if (bivideo_init(&sc->sc_fbconf) != 0) {
165659f65e0Such /* just return so that hpcfb will not be attached */
166659f65e0Such return;
167659f65e0Such }
168659f65e0Such
169659f65e0Such printf("pseudo video controller");
170659f65e0Such if (console_flag) {
171659f65e0Such printf(", console");
172659f65e0Such }
173659f65e0Such printf("\n");
174659f65e0Such printf("%s: framebuffer address: 0x%08lx\n",
175cbab9cadSchs device_xname(self), (u_long)bootinfo->fb_addr);
176659f65e0Such
177659f65e0Such /* Add a suspend hook to power saving */
178659f65e0Such sc->sc_powerstate = 0;
179f928eeabStsutsui if (!pmf_device_register(self, bivideo_suspend, bivideo_resume))
180f928eeabStsutsui aprint_error_dev(self, "unable to establish power handler\n");
181659f65e0Such
182b8e5bc56Ssato /* initialize backlight brightness and lcd contrast */
1836c5da9bdSsato sc->sc_lcd_inited = 0;
1846c5da9bdSsato bivideo_init_brightness(sc, 1);
1856c5da9bdSsato bivideo_init_contrast(sc, 1);
1866c5da9bdSsato bivideo_init_backlight(sc, 1);
187b8e5bc56Ssato
188659f65e0Such ha.ha_console = console_flag;
189659f65e0Such ha.ha_accessops = &bivideo_ha;
190659f65e0Such ha.ha_accessctx = sc;
191659f65e0Such ha.ha_curfbconf = 0;
192659f65e0Such ha.ha_nfbconf = 1;
193659f65e0Such ha.ha_fbconflist = &sc->sc_fbconf;
194659f65e0Such ha.ha_curdspconf = 0;
195659f65e0Such ha.ha_ndspconf = 1;
196659f65e0Such ha.ha_dspconflist = &sc->sc_dspconf;
197659f65e0Such
198c7fb772bSthorpej config_found(self, &ha, hpcfbprint, CFARGS_NONE);
199659f65e0Such }
200659f65e0Such
201659f65e0Such int
bivideo_getcnfb(struct hpcfb_fbconf * fb)202edde743dSuch bivideo_getcnfb(struct hpcfb_fbconf *fb)
203659f65e0Such {
204659f65e0Such console_flag = 1;
205659f65e0Such
206659f65e0Such return bivideo_init(fb);
207659f65e0Such }
208659f65e0Such
209659f65e0Such static int
bivideo_init(struct hpcfb_fbconf * fb)210edde743dSuch bivideo_init(struct hpcfb_fbconf *fb)
211659f65e0Such {
212659f65e0Such /*
213659f65e0Such * get fb settings from bootinfo
214659f65e0Such */
215659f65e0Such if (bootinfo == NULL ||
216659f65e0Such bootinfo->fb_addr == 0 ||
217659f65e0Such bootinfo->fb_line_bytes == 0 ||
218659f65e0Such bootinfo->fb_width == 0 ||
219659f65e0Such bootinfo->fb_height == 0) {
220e267c67bStoshii printf("no frame buffer information.\n");
221659f65e0Such return (-1);
222659f65e0Such }
223659f65e0Such
224659f65e0Such /* zero fill */
22535836fceStoshii memset(fb, 0, sizeof(*fb));
226659f65e0Such
227659f65e0Such fb->hf_conf_index = 0; /* configuration index */
228659f65e0Such fb->hf_nconfs = 1; /* how many configurations */
229659f65e0Such strcpy(fb->hf_name, "built-in video");
230659f65e0Such /* frame buffer name */
231659f65e0Such strcpy(fb->hf_conf_name, "default");
232659f65e0Such /* configuration name */
233659f65e0Such fb->hf_height = bootinfo->fb_height;
234659f65e0Such fb->hf_width = bootinfo->fb_width;
235659f65e0Such fb->hf_baseaddr = (u_long)bootinfo->fb_addr;
236659f65e0Such fb->hf_offset = (u_long)bootinfo->fb_addr -
237edde743dSuch __PTOB(__BTOP(bootinfo->fb_addr));
238659f65e0Such /* frame buffer start offset */
239659f65e0Such fb->hf_bytes_per_line = bootinfo->fb_line_bytes;
240659f65e0Such fb->hf_nplanes = 1;
241659f65e0Such fb->hf_bytes_per_plane = bootinfo->fb_height *
242659f65e0Such bootinfo->fb_line_bytes;
243659f65e0Such
244659f65e0Such fb->hf_access_flags |= HPCFB_ACCESS_BYTE;
245659f65e0Such fb->hf_access_flags |= HPCFB_ACCESS_WORD;
246659f65e0Such fb->hf_access_flags |= HPCFB_ACCESS_DWORD;
247659f65e0Such
248659f65e0Such switch (bootinfo->fb_type) {
249659f65e0Such /*
250659f65e0Such * gray scale
251659f65e0Such */
252659f65e0Such case BIFB_D2_M2L_3:
253659f65e0Such case BIFB_D2_M2L_3x2:
254659f65e0Such fb->hf_access_flags |= HPCFB_ACCESS_REVERSE;
255659f65e0Such /* fall through */
256659f65e0Such case BIFB_D2_M2L_0:
257659f65e0Such case BIFB_D2_M2L_0x2:
258659f65e0Such fb->hf_class = HPCFB_CLASS_GRAYSCALE;
259659f65e0Such fb->hf_access_flags |= HPCFB_ACCESS_STATIC;
260659f65e0Such fb->hf_pack_width = 8;
261659f65e0Such fb->hf_pixels_per_pack = 4;
262659f65e0Such fb->hf_pixel_width = 2;
263659f65e0Such fb->hf_class_data_length = sizeof(struct hf_gray_tag);
264659f65e0Such fb->hf_u.hf_gray.hf_flags = 0; /* reserved for future use */
265659f65e0Such break;
266659f65e0Such
267659f65e0Such case BIFB_D4_M2L_F:
268659f65e0Such case BIFB_D4_M2L_Fx2:
269659f65e0Such fb->hf_access_flags |= HPCFB_ACCESS_REVERSE;
270659f65e0Such /* fall through */
271659f65e0Such case BIFB_D4_M2L_0:
272659f65e0Such case BIFB_D4_M2L_0x2:
273659f65e0Such fb->hf_class = HPCFB_CLASS_GRAYSCALE;
274659f65e0Such fb->hf_access_flags |= HPCFB_ACCESS_STATIC;
275659f65e0Such fb->hf_pack_width = 8;
276659f65e0Such fb->hf_pixels_per_pack = 2;
277659f65e0Such fb->hf_pixel_width = 4;
278659f65e0Such fb->hf_class_data_length = sizeof(struct hf_gray_tag);
279659f65e0Such fb->hf_u.hf_gray.hf_flags = 0; /* reserved for future use */
280659f65e0Such break;
281659f65e0Such
282659f65e0Such /*
283659f65e0Such * indexed color
284659f65e0Such */
285659f65e0Such case BIFB_D8_FF:
286659f65e0Such fb->hf_access_flags |= HPCFB_ACCESS_REVERSE;
287659f65e0Such /* fall through */
288659f65e0Such case BIFB_D8_00:
289659f65e0Such fb->hf_class = HPCFB_CLASS_INDEXCOLOR;
290659f65e0Such fb->hf_access_flags |= HPCFB_ACCESS_STATIC;
291659f65e0Such fb->hf_pack_width = 8;
292659f65e0Such fb->hf_pixels_per_pack = 1;
293659f65e0Such fb->hf_pixel_width = 8;
294659f65e0Such fb->hf_class_data_length = sizeof(struct hf_indexed_tag);
295659f65e0Such fb->hf_u.hf_indexed.hf_flags = 0; /* reserved for future use */
296659f65e0Such break;
297659f65e0Such
298659f65e0Such /*
299659f65e0Such * RGB color
300659f65e0Such */
301659f65e0Such case BIFB_D16_FFFF:
302659f65e0Such fb->hf_access_flags |= HPCFB_ACCESS_REVERSE;
303659f65e0Such /* fall through */
304659f65e0Such case BIFB_D16_0000:
305659f65e0Such fb->hf_class = HPCFB_CLASS_RGBCOLOR;
306659f65e0Such fb->hf_access_flags |= HPCFB_ACCESS_STATIC;
30764b6b76aStakemura #if BYTE_ORDER == LITTLE_ENDIAN
30864b6b76aStakemura fb->hf_order_flags = HPCFB_REVORDER_BYTE;
309659f65e0Such #endif
310659f65e0Such fb->hf_pack_width = 16;
311659f65e0Such fb->hf_pixels_per_pack = 1;
312659f65e0Such fb->hf_pixel_width = 16;
313659f65e0Such
314659f65e0Such fb->hf_class_data_length = sizeof(struct hf_rgb_tag);
315659f65e0Such fb->hf_u.hf_rgb.hf_flags = 0; /* reserved for future use */
316659f65e0Such
317659f65e0Such fb->hf_u.hf_rgb.hf_red_width = 5;
318659f65e0Such fb->hf_u.hf_rgb.hf_red_shift = 11;
319659f65e0Such fb->hf_u.hf_rgb.hf_green_width = 6;
320659f65e0Such fb->hf_u.hf_rgb.hf_green_shift = 5;
321659f65e0Such fb->hf_u.hf_rgb.hf_blue_width = 5;
322659f65e0Such fb->hf_u.hf_rgb.hf_blue_shift = 0;
323659f65e0Such fb->hf_u.hf_rgb.hf_alpha_width = 0;
324659f65e0Such fb->hf_u.hf_rgb.hf_alpha_shift = 0;
325659f65e0Such break;
326659f65e0Such
327659f65e0Such default:
328659f65e0Such printf("unsupported type %d.\n", bootinfo->fb_type);
329659f65e0Such return (-1);
330659f65e0Such break;
331659f65e0Such }
332659f65e0Such
333659f65e0Such return (0); /* no error */
334659f65e0Such }
335659f65e0Such
336659f65e0Such static void
bivideo_power(int why,void * arg)337edde743dSuch bivideo_power(int why, void *arg)
338659f65e0Such {
339659f65e0Such struct bivideo_softc *sc = arg;
340659f65e0Such
341659f65e0Such switch (why) {
342659f65e0Such case PWR_SUSPEND:
343659f65e0Such case PWR_STANDBY:
344659f65e0Such sc->sc_powerstate |= PWRSTAT_SUSPEND;
345659f65e0Such bivideo_update_powerstate(sc, PWRSTAT_ALL);
346659f65e0Such break;
347659f65e0Such case PWR_RESUME:
348659f65e0Such sc->sc_powerstate &= ~PWRSTAT_SUSPEND;
349659f65e0Such bivideo_update_powerstate(sc, PWRSTAT_ALL);
350659f65e0Such break;
351659f65e0Such }
352659f65e0Such }
353659f65e0Such
354659f65e0Such static void
bivideo_update_powerstate(struct bivideo_softc * sc,int updates)355edde743dSuch bivideo_update_powerstate(struct bivideo_softc *sc, int updates)
356659f65e0Such {
357659f65e0Such if (updates & PWRSTAT_LCD)
358659f65e0Such config_hook_call(CONFIG_HOOK_POWERCONTROL,
359659f65e0Such CONFIG_HOOK_POWERCONTROL_LCD,
36080214041Ssato (void*)!(sc->sc_powerstate &
36180214041Ssato (PWRSTAT_VIDEOOFF|PWRSTAT_SUSPEND)));
362659f65e0Such
363659f65e0Such if (updates & PWRSTAT_BACKLIGHT)
364659f65e0Such config_hook_call(CONFIG_HOOK_POWERCONTROL,
365659f65e0Such CONFIG_HOOK_POWERCONTROL_LCDLIGHT,
36680214041Ssato (void*)(!(sc->sc_powerstate &
36780214041Ssato (PWRSTAT_VIDEOOFF|PWRSTAT_SUSPEND)) &&
368659f65e0Such (sc->sc_powerstate & PWRSTAT_BACKLIGHT)));
369659f65e0Such }
370659f65e0Such
371f928eeabStsutsui static bool
bivideo_suspend(device_t self,const pmf_qual_t * qual)372f928eeabStsutsui bivideo_suspend(device_t self, const pmf_qual_t *qual)
373f928eeabStsutsui {
374f928eeabStsutsui struct bivideo_softc *sc = device_private(self);
375f928eeabStsutsui
376f928eeabStsutsui bivideo_power(PWR_SUSPEND, sc);
377f928eeabStsutsui return true;
378f928eeabStsutsui }
379f928eeabStsutsui
380f928eeabStsutsui static bool
bivideo_resume(device_t self,const pmf_qual_t * qual)381f928eeabStsutsui bivideo_resume(device_t self, const pmf_qual_t *qual)
382f928eeabStsutsui {
383f928eeabStsutsui struct bivideo_softc *sc = device_private(self);
384f928eeabStsutsui
385f928eeabStsutsui bivideo_power(PWR_RESUME, sc);
386f928eeabStsutsui return true;
387f928eeabStsutsui }
388f928eeabStsutsui
389659f65e0Such int
bivideo_ioctl(void * v,u_long cmd,void * data,int flag,struct lwp * l)39053524e44Schristos bivideo_ioctl(void *v, u_long cmd, void *data, int flag, struct lwp *l)
391659f65e0Such {
392659f65e0Such struct bivideo_softc *sc = (struct bivideo_softc *)v;
393659f65e0Such struct hpcfb_fbconf *fbconf;
394659f65e0Such struct hpcfb_dspconf *dspconf;
395659f65e0Such struct wsdisplay_cmap *cmap;
396659f65e0Such struct wsdisplay_param *dispparam;
397e07f0b93Schs int error;
398659f65e0Such
399659f65e0Such switch (cmd) {
400659f65e0Such case WSDISPLAYIO_GETCMAP:
401659f65e0Such cmap = (struct wsdisplay_cmap *)data;
402659f65e0Such
403659f65e0Such if (sc->sc_fbconf.hf_class != HPCFB_CLASS_INDEXCOLOR ||
404659f65e0Such sc->sc_fbconf.hf_pack_width != 8 ||
4054b70fd12Sspz cmap->index >= 256 ||
4064b70fd12Sspz cmap->count > 256 - cmap->index)
407659f65e0Such return (EINVAL);
408659f65e0Such
409e07f0b93Schs error = copyout(&bivideo_cmap_r[cmap->index], cmap->red,
410e07f0b93Schs cmap->count);
411e07f0b93Schs if (error)
412e07f0b93Schs return error;
413e07f0b93Schs error = copyout(&bivideo_cmap_g[cmap->index], cmap->green,
414e07f0b93Schs cmap->count);
415e07f0b93Schs if (error)
416e07f0b93Schs return error;
417e07f0b93Schs error = copyout(&bivideo_cmap_b[cmap->index], cmap->blue,
418e07f0b93Schs cmap->count);
419e07f0b93Schs return error;
420659f65e0Such
421659f65e0Such case WSDISPLAYIO_PUTCMAP:
422659f65e0Such /*
423659f65e0Such * This driver can't set color map.
424659f65e0Such */
425659f65e0Such return (EINVAL);
426659f65e0Such
42780214041Ssato case WSDISPLAYIO_SVIDEO:
42880214041Ssato if (*(int *)data == WSDISPLAYIO_VIDEO_OFF)
42980214041Ssato sc->sc_powerstate |= PWRSTAT_VIDEOOFF;
43080214041Ssato else
43180214041Ssato sc->sc_powerstate &= ~PWRSTAT_VIDEOOFF;
43280214041Ssato bivideo_update_powerstate(sc, PWRSTAT_ALL);
43380214041Ssato return 0;
43480214041Ssato
43580214041Ssato case WSDISPLAYIO_GVIDEO:
43680214041Ssato *(int *)data = (sc->sc_powerstate&PWRSTAT_VIDEOOFF) ?
43780214041Ssato WSDISPLAYIO_VIDEO_OFF:WSDISPLAYIO_VIDEO_ON;
43880214041Ssato return 0;
43980214041Ssato
440b8e5bc56Ssato
441659f65e0Such case WSDISPLAYIO_GETPARAM:
442659f65e0Such dispparam = (struct wsdisplay_param*)data;
443659f65e0Such switch (dispparam->param) {
444659f65e0Such case WSDISPLAYIO_PARAM_BACKLIGHT:
4456c5da9bdSsato VPRINTF(("bivideo_ioctl: GET:BACKLIGHT\n"));
4466c5da9bdSsato bivideo_init_brightness(sc, 0);
4476c5da9bdSsato bivideo_init_backlight(sc, 0);
4486c5da9bdSsato VPRINTF(("bivideo_ioctl: GET:(real)BACKLIGHT %d\n",
4496c5da9bdSsato (sc->sc_powerstate&PWRSTAT_BACKLIGHT)? 1: 0));
450659f65e0Such dispparam->min = 0;
451659f65e0Such dispparam->max = 1;
452b8e5bc56Ssato if (sc->sc_max_brightness > 0)
453b8e5bc56Ssato dispparam->curval = sc->sc_brightness > 0? 1: 0;
454b8e5bc56Ssato else
455659f65e0Such dispparam->curval =
456659f65e0Such (sc->sc_powerstate&PWRSTAT_BACKLIGHT) ? 1: 0;
4576c5da9bdSsato VPRINTF(("bivideo_ioctl: GET:BACKLIGHT:%d(%s)\n",
4586c5da9bdSsato dispparam->curval,
4596c5da9bdSsato sc->sc_max_brightness > 0? "brightness": "light"));
460b8e5bc56Ssato return 0;
461659f65e0Such break;
462659f65e0Such case WSDISPLAYIO_PARAM_CONTRAST:
4636c5da9bdSsato VPRINTF(("bivideo_ioctl: GET:CONTRAST\n"));
4646c5da9bdSsato bivideo_init_contrast(sc, 0);
465b8e5bc56Ssato if (sc->sc_max_contrast > 0) {
466b8e5bc56Ssato dispparam->min = 0;
467b8e5bc56Ssato dispparam->max = sc->sc_max_contrast;
468b8e5bc56Ssato dispparam->curval = sc->sc_contrast;
4696c5da9bdSsato VPRINTF(("bivideo_ioctl: GET:CONTRAST max=%d, current=%d\n", sc->sc_max_contrast, sc->sc_contrast));
470b8e5bc56Ssato return 0;
471b8e5bc56Ssato } else {
4726c5da9bdSsato VPRINTF(("bivideo_ioctl: GET:CONTRAST EINVAL\n"));
473659f65e0Such return (EINVAL);
474b8e5bc56Ssato }
475b8e5bc56Ssato break;
476659f65e0Such case WSDISPLAYIO_PARAM_BRIGHTNESS:
4776c5da9bdSsato VPRINTF(("bivideo_ioctl: GET:BRIGHTNESS\n"));
4786c5da9bdSsato bivideo_init_brightness(sc, 0);
479b8e5bc56Ssato if (sc->sc_max_brightness > 0) {
480b8e5bc56Ssato dispparam->min = 0;
481b8e5bc56Ssato dispparam->max = sc->sc_max_brightness;
482b8e5bc56Ssato dispparam->curval = sc->sc_brightness;
4836c5da9bdSsato VPRINTF(("bivideo_ioctl: GET:BRIGHTNESS max=%d, current=%d\n", sc->sc_max_brightness, sc->sc_brightness));
484b8e5bc56Ssato return 0;
485b8e5bc56Ssato } else {
4866c5da9bdSsato VPRINTF(("bivideo_ioctl: GET:BRIGHTNESS EINVAL\n"));
487b8e5bc56Ssato return (EINVAL);
488b8e5bc56Ssato }
489659f65e0Such return (EINVAL);
490659f65e0Such default:
491659f65e0Such return (EINVAL);
492659f65e0Such }
493659f65e0Such return (0);
494659f65e0Such
495659f65e0Such case WSDISPLAYIO_SETPARAM:
496659f65e0Such dispparam = (struct wsdisplay_param*)data;
497659f65e0Such switch (dispparam->param) {
498659f65e0Such case WSDISPLAYIO_PARAM_BACKLIGHT:
4996c5da9bdSsato VPRINTF(("bivideo_ioctl: SET:BACKLIGHT\n"));
500659f65e0Such if (dispparam->curval < 0 ||
501659f65e0Such 1 < dispparam->curval)
502659f65e0Such return (EINVAL);
5036c5da9bdSsato bivideo_init_brightness(sc, 0);
5046c5da9bdSsato VPRINTF(("bivideo_ioctl: SET:max brightness=%d\n", sc->sc_max_brightness));
505b8e5bc56Ssato if (sc->sc_max_brightness > 0) { /* dimmer */
506b8e5bc56Ssato if (dispparam->curval == 0){
507b8e5bc56Ssato sc->sc_brightness_save = sc->sc_brightness;
508b8e5bc56Ssato bivideo_set_brightness(sc, 0); /* min */
509b8e5bc56Ssato } else {
510b8e5bc56Ssato if (sc->sc_brightness_save == 0)
511b8e5bc56Ssato sc->sc_brightness_save = sc->sc_max_brightness;
512b8e5bc56Ssato bivideo_set_brightness(sc, sc->sc_brightness_save);
513b8e5bc56Ssato }
5146c5da9bdSsato VPRINTF(("bivideo_ioctl: SET:BACKLIGHT:brightness=%d\n", sc->sc_brightness));
515b8e5bc56Ssato } else { /* off */
516659f65e0Such if (dispparam->curval == 0)
517659f65e0Such sc->sc_powerstate &= ~PWRSTAT_BACKLIGHT;
518659f65e0Such else
519659f65e0Such sc->sc_powerstate |= PWRSTAT_BACKLIGHT;
5206c5da9bdSsato VPRINTF(("bivideo_ioctl: SET:BACKLIGHT:powerstate %d\n",
521b8e5bc56Ssato (sc->sc_powerstate & PWRSTAT_BACKLIGHT)?1:0));
522659f65e0Such bivideo_update_powerstate(sc, PWRSTAT_BACKLIGHT);
5236c5da9bdSsato VPRINTF(("bivideo_ioctl: SET:BACKLIGHT:%d\n",
524659f65e0Such (sc->sc_powerstate & PWRSTAT_BACKLIGHT)?1:0));
525b8e5bc56Ssato }
526b8e5bc56Ssato return 0;
527659f65e0Such break;
528659f65e0Such case WSDISPLAYIO_PARAM_CONTRAST:
5296c5da9bdSsato VPRINTF(("bivideo_ioctl: SET:CONTRAST\n"));
5306c5da9bdSsato bivideo_init_contrast(sc, 0);
531b8e5bc56Ssato if (dispparam->curval < 0 ||
532b8e5bc56Ssato sc->sc_max_contrast < dispparam->curval)
533659f65e0Such return (EINVAL);
534b8e5bc56Ssato if (sc->sc_max_contrast > 0) {
5354072b525She #ifdef FBDEBUG
536b8e5bc56Ssato int org = sc->sc_contrast;
5374072b525She #endif
538b8e5bc56Ssato bivideo_set_contrast(sc, dispparam->curval);
5396c5da9bdSsato VPRINTF(("bivideo_ioctl: SET:CONTRAST org=%d, current=%d\n", org, sc->sc_contrast));
540b8e5bc56Ssato return 0;
541b8e5bc56Ssato } else {
5426c5da9bdSsato VPRINTF(("bivideo_ioctl: SET:CONTRAST EINVAL\n"));
543b8e5bc56Ssato return (EINVAL);
544b8e5bc56Ssato }
545b8e5bc56Ssato break;
546659f65e0Such case WSDISPLAYIO_PARAM_BRIGHTNESS:
5476c5da9bdSsato VPRINTF(("bivideo_ioctl: SET:BRIGHTNESS\n"));
5486c5da9bdSsato bivideo_init_brightness(sc, 0);
549b8e5bc56Ssato if (dispparam->curval < 0 ||
550b8e5bc56Ssato sc->sc_max_brightness < dispparam->curval)
551659f65e0Such return (EINVAL);
552b8e5bc56Ssato if (sc->sc_max_brightness > 0) {
5534072b525She #ifdef FBDEBUG
554b8e5bc56Ssato int org = sc->sc_brightness;
5554072b525She #endif
556b8e5bc56Ssato bivideo_set_brightness(sc, dispparam->curval);
5576c5da9bdSsato VPRINTF(("bivideo_ioctl: SET:BRIGHTNESS org=%d, current=%d\n", org, sc->sc_brightness));
558b8e5bc56Ssato return 0;
559b8e5bc56Ssato } else {
5606c5da9bdSsato VPRINTF(("bivideo_ioctl: SET:BRIGHTNESS EINVAL\n"));
561b8e5bc56Ssato return (EINVAL);
562b8e5bc56Ssato }
563b8e5bc56Ssato break;
564659f65e0Such default:
565659f65e0Such return (EINVAL);
566659f65e0Such }
567659f65e0Such return (0);
568659f65e0Such
569659f65e0Such case HPCFBIO_GCONF:
570659f65e0Such fbconf = (struct hpcfb_fbconf *)data;
571659f65e0Such if (fbconf->hf_conf_index != 0 &&
572659f65e0Such fbconf->hf_conf_index != HPCFB_CURRENT_CONFIG) {
573659f65e0Such return (EINVAL);
574659f65e0Such }
575659f65e0Such *fbconf = sc->sc_fbconf; /* structure assignment */
576659f65e0Such return (0);
577659f65e0Such case HPCFBIO_SCONF:
578659f65e0Such fbconf = (struct hpcfb_fbconf *)data;
579659f65e0Such if (fbconf->hf_conf_index != 0 &&
580659f65e0Such fbconf->hf_conf_index != HPCFB_CURRENT_CONFIG) {
581659f65e0Such return (EINVAL);
582659f65e0Such }
583659f65e0Such /*
584964859d8Sabs * nothing to do because we have only one configuration
585659f65e0Such */
586659f65e0Such return (0);
587659f65e0Such case HPCFBIO_GDSPCONF:
588659f65e0Such dspconf = (struct hpcfb_dspconf *)data;
589659f65e0Such if ((dspconf->hd_unit_index != 0 &&
590659f65e0Such dspconf->hd_unit_index != HPCFB_CURRENT_UNIT) ||
591659f65e0Such (dspconf->hd_conf_index != 0 &&
592659f65e0Such dspconf->hd_conf_index != HPCFB_CURRENT_CONFIG)) {
593659f65e0Such return (EINVAL);
594659f65e0Such }
595659f65e0Such *dspconf = sc->sc_dspconf; /* structure assignment */
596659f65e0Such return (0);
597659f65e0Such case HPCFBIO_SDSPCONF:
598659f65e0Such dspconf = (struct hpcfb_dspconf *)data;
599659f65e0Such if ((dspconf->hd_unit_index != 0 &&
600659f65e0Such dspconf->hd_unit_index != HPCFB_CURRENT_UNIT) ||
601659f65e0Such (dspconf->hd_conf_index != 0 &&
602659f65e0Such dspconf->hd_conf_index != HPCFB_CURRENT_CONFIG)) {
603659f65e0Such return (EINVAL);
604659f65e0Such }
605659f65e0Such /*
606659f65e0Such * nothing to do
607964859d8Sabs * because we have only one unit and one configuration
608659f65e0Such */
609659f65e0Such return (0);
610659f65e0Such case HPCFBIO_GOP:
611659f65e0Such case HPCFBIO_SOP:
612659f65e0Such /*
613*86c30724Sandvar * currently not implemented...
614659f65e0Such */
615659f65e0Such return (EINVAL);
616659f65e0Such }
617659f65e0Such
61831144d99Satatat return (EPASSTHROUGH);
619659f65e0Such }
620659f65e0Such
621659f65e0Such paddr_t
bivideo_mmap(void * ctx,off_t offset,int prot)622edde743dSuch bivideo_mmap(void *ctx, off_t offset, int prot)
623659f65e0Such {
624659f65e0Such struct bivideo_softc *sc = (struct bivideo_softc *)ctx;
625659f65e0Such
626659f65e0Such if (offset < 0 ||
627659f65e0Such (sc->sc_fbconf.hf_bytes_per_plane +
628659f65e0Such sc->sc_fbconf.hf_offset) < offset)
629659f65e0Such return -1;
630659f65e0Such
631edde743dSuch return __BTOP((u_long)bootinfo->fb_addr + offset);
632659f65e0Such }
633b8e5bc56Ssato
6346c5da9bdSsato
635b8e5bc56Ssato void
bivideo_init_backlight(struct bivideo_softc * sc,int inattach)6366c5da9bdSsato bivideo_init_backlight(struct bivideo_softc *sc, int inattach)
637b8e5bc56Ssato {
638b8e5bc56Ssato int val = -1;
639b8e5bc56Ssato
6406c5da9bdSsato if (sc->sc_lcd_inited&BACKLIGHT_INITED)
6416c5da9bdSsato return;
6426c5da9bdSsato
643b8e5bc56Ssato if (config_hook_call(CONFIG_HOOK_GET,
644b8e5bc56Ssato CONFIG_HOOK_POWER_LCDLIGHT, &val) != -1) {
6456c5da9bdSsato /* we can get real light state */
6466c5da9bdSsato VPRINTF(("bivideo_init_backlight: real backlight=%d\n", val));
647b8e5bc56Ssato if (val == 0)
648b8e5bc56Ssato sc->sc_powerstate &= ~PWRSTAT_BACKLIGHT;
649b8e5bc56Ssato else
650b8e5bc56Ssato sc->sc_powerstate |= PWRSTAT_BACKLIGHT;
6516c5da9bdSsato sc->sc_lcd_inited |= BACKLIGHT_INITED;
6526c5da9bdSsato } else if (inattach) {
6536c5da9bdSsato /*
6546c5da9bdSsato we cannot get real light state in attach time
6556c5da9bdSsato because light device not yet attached.
6566c5da9bdSsato we will retry in !inattach.
6576c5da9bdSsato temporary assume light is on.
6586c5da9bdSsato */
659ee1d25e7Ssato sc->sc_powerstate |= PWRSTAT_BACKLIGHT;
6606c5da9bdSsato } else {
6616c5da9bdSsato /* we cannot get real light state, so work by myself state */
6626c5da9bdSsato sc->sc_lcd_inited |= BACKLIGHT_INITED;
6636c5da9bdSsato }
664b8e5bc56Ssato }
665b8e5bc56Ssato
666b8e5bc56Ssato void
bivideo_init_brightness(struct bivideo_softc * sc,int inattach)6676c5da9bdSsato bivideo_init_brightness(struct bivideo_softc *sc, int inattach)
668b8e5bc56Ssato {
669b8e5bc56Ssato int val = -1;
670b8e5bc56Ssato
6716c5da9bdSsato if (sc->sc_lcd_inited&BRIGHTNESS_INITED)
6726c5da9bdSsato return;
6736c5da9bdSsato
6746c5da9bdSsato VPRINTF(("bivideo_init_brightness\n"));
675b8e5bc56Ssato if (config_hook_call(CONFIG_HOOK_GET,
676b8e5bc56Ssato CONFIG_HOOK_BRIGHTNESS_MAX, &val) != -1) {
6776c5da9bdSsato /* we can get real brightness max */
6786c5da9bdSsato VPRINTF(("bivideo_init_brightness: real brightness max=%d\n", val));
679b8e5bc56Ssato sc->sc_max_brightness = val;
6806c5da9bdSsato val = -1;
6816c5da9bdSsato if (config_hook_call(CONFIG_HOOK_GET,
6826c5da9bdSsato CONFIG_HOOK_BRIGHTNESS, &val) != -1) {
6836c5da9bdSsato /* we can get real brightness */
6846c5da9bdSsato VPRINTF(("bivideo_init_brightness: real brightness=%d\n", val));
6856c5da9bdSsato sc->sc_brightness_save = sc->sc_brightness = val;
6866c5da9bdSsato } else {
6876c5da9bdSsato sc->sc_brightness_save =
6886c5da9bdSsato sc->sc_brightness = sc->sc_max_brightness;
689b8e5bc56Ssato }
6906c5da9bdSsato sc->sc_lcd_inited |= BRIGHTNESS_INITED;
6916c5da9bdSsato } else if (inattach) {
6926c5da9bdSsato /*
6936c5da9bdSsato we cannot get real brightness in attach time
6946c5da9bdSsato because brightness device not yet attached.
6956c5da9bdSsato we will retry in !inattach.
6966c5da9bdSsato */
6976c5da9bdSsato sc->sc_max_brightness = -1;
6986c5da9bdSsato sc->sc_brightness = -1;
6996c5da9bdSsato sc->sc_brightness_save = -1;
7006c5da9bdSsato } else {
7016c5da9bdSsato /* we cannot get real brightness */
7026c5da9bdSsato sc->sc_lcd_inited |= BRIGHTNESS_INITED;
7036c5da9bdSsato }
7046c5da9bdSsato
705b8e5bc56Ssato return;
706b8e5bc56Ssato }
707b8e5bc56Ssato
708b8e5bc56Ssato void
bivideo_init_contrast(struct bivideo_softc * sc,int inattach)7096c5da9bdSsato bivideo_init_contrast(struct bivideo_softc *sc, int inattach)
710b8e5bc56Ssato {
711b8e5bc56Ssato int val = -1;
712b8e5bc56Ssato
7136c5da9bdSsato if (sc->sc_lcd_inited&CONTRAST_INITED)
7146c5da9bdSsato return;
7156c5da9bdSsato
7166c5da9bdSsato VPRINTF(("bivideo_init_contrast\n"));
717b8e5bc56Ssato if (config_hook_call(CONFIG_HOOK_GET,
718b8e5bc56Ssato CONFIG_HOOK_CONTRAST_MAX, &val) != -1) {
7196c5da9bdSsato /* we can get real contrast max */
7206c5da9bdSsato VPRINTF(("bivideo_init_contrast: real contrast max=%d\n", val));
721b8e5bc56Ssato sc->sc_max_contrast = val;
7226c5da9bdSsato val = -1;
7236c5da9bdSsato if (config_hook_call(CONFIG_HOOK_GET,
7246c5da9bdSsato CONFIG_HOOK_CONTRAST, &val) != -1) {
7256c5da9bdSsato /* we can get real contrast */
7266c5da9bdSsato VPRINTF(("bivideo_init_contrast: real contrast=%d\n", val));
7276c5da9bdSsato sc->sc_contrast = val;
7286c5da9bdSsato } else {
7296c5da9bdSsato sc->sc_contrast = sc->sc_max_contrast;
730b8e5bc56Ssato }
7316c5da9bdSsato sc->sc_lcd_inited |= CONTRAST_INITED;
7326c5da9bdSsato } else if (inattach) {
7336c5da9bdSsato /*
7346c5da9bdSsato we cannot get real contrast in attach time
7356c5da9bdSsato because contrast device not yet attached.
7366c5da9bdSsato we will retry in !inattach.
7376c5da9bdSsato */
7386c5da9bdSsato sc->sc_max_contrast = -1;
7396c5da9bdSsato sc->sc_contrast = -1;
7406c5da9bdSsato } else {
7416c5da9bdSsato /* we cannot get real contrast */
7426c5da9bdSsato sc->sc_lcd_inited |= CONTRAST_INITED;
7436c5da9bdSsato }
7446c5da9bdSsato
745b8e5bc56Ssato return;
746b8e5bc56Ssato }
747b8e5bc56Ssato
748b8e5bc56Ssato void
bivideo_set_brightness(struct bivideo_softc * sc,int val)749b8e5bc56Ssato bivideo_set_brightness(struct bivideo_softc *sc, int val)
750b8e5bc56Ssato {
751b8e5bc56Ssato sc->sc_brightness = val;
752b8e5bc56Ssato
753b8e5bc56Ssato config_hook_call(CONFIG_HOOK_SET, CONFIG_HOOK_BRIGHTNESS, &val);
754b8e5bc56Ssato if (config_hook_call(CONFIG_HOOK_GET,
755b8e5bc56Ssato CONFIG_HOOK_BRIGHTNESS, &val) != -1) {
756b8e5bc56Ssato sc->sc_brightness = val;
757b8e5bc56Ssato }
758b8e5bc56Ssato }
759b8e5bc56Ssato
760b8e5bc56Ssato void
bivideo_set_contrast(struct bivideo_softc * sc,int val)761b8e5bc56Ssato bivideo_set_contrast(struct bivideo_softc *sc, int val)
762b8e5bc56Ssato {
763b8e5bc56Ssato sc->sc_contrast = val;
764b8e5bc56Ssato
765b8e5bc56Ssato config_hook_call(CONFIG_HOOK_SET, CONFIG_HOOK_CONTRAST, &val);
766b8e5bc56Ssato if (config_hook_call(CONFIG_HOOK_GET,
767b8e5bc56Ssato CONFIG_HOOK_CONTRAST, &val) != -1) {
768b8e5bc56Ssato sc->sc_contrast = val;
769b8e5bc56Ssato }
770b8e5bc56Ssato }
771