Branch data Line data Source code
1 : : /*
2 : : * This program is free software; you can redistribute it and/or modify
3 : : * it under the terms of the GNU General Public License version 2 as
4 : : * published by the Free Software Foundation.
5 : : *
6 : : * This program is distributed in the hope that it will be useful,
7 : : * but WITHOUT ANY WARRANTY; without even the implied warranty of
8 : : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
9 : : * GNU General Public License for more details.
10 : : *
11 : : * Copyright (C) 2012 ARM Limited
12 : : */
13 : :
14 : : #define pr_fmt(fmt) "vexpress-dvi: " fmt
15 : :
16 : : #include <linux/fb.h>
17 : : #include <linux/of.h>
18 : : #include <linux/of_device.h>
19 : : #include <linux/vexpress.h>
20 : :
21 : :
22 : : static struct vexpress_config_func *vexpress_dvimode_func;
23 : :
24 : : static struct {
25 : : u32 xres, yres, mode;
26 : : } vexpress_dvi_dvimodes[] = {
27 : : { 640, 480, 0 }, /* VGA */
28 : : { 800, 600, 1 }, /* SVGA */
29 : : { 1024, 768, 2 }, /* XGA */
30 : : { 1280, 1024, 3 }, /* SXGA */
31 : : { 1600, 1200, 4 }, /* UXGA */
32 : : { 1920, 1080, 5 }, /* HD1080 */
33 : : };
34 : :
35 : 0 : static void vexpress_dvi_mode_set(struct fb_info *info, u32 xres, u32 yres)
36 : : {
37 : : int err = -ENOENT;
38 : : int i;
39 : :
40 [ # # ]: 0 : if (!vexpress_dvimode_func)
41 : 0 : return;
42 : :
43 [ # # ]: 0 : for (i = 0; i < ARRAY_SIZE(vexpress_dvi_dvimodes); i++) {
44 [ # # ][ # # ]: 0 : if (vexpress_dvi_dvimodes[i].xres == xres &&
45 : 0 : vexpress_dvi_dvimodes[i].yres == yres) {
46 : : pr_debug("mode: %ux%u = %d\n", xres, yres,
47 : : vexpress_dvi_dvimodes[i].mode);
48 : 0 : err = vexpress_config_write(vexpress_dvimode_func, 0,
49 : : vexpress_dvi_dvimodes[i].mode);
50 : : break;
51 : : }
52 : : }
53 : :
54 [ # # ]: 0 : if (err)
55 : 0 : pr_warn("Failed to set %ux%u mode! (%d)\n", xres, yres, err);
56 : : }
57 : :
58 : :
59 : : static struct vexpress_config_func *vexpress_muxfpga_func;
60 : : static int vexpress_dvi_fb = -1;
61 : :
62 : 0 : static int vexpress_dvi_mux_set(struct fb_info *info)
63 : : {
64 : : int err;
65 : 0 : u32 site = vexpress_get_site_by_dev(info->device);
66 : :
67 [ # # ]: 0 : if (!vexpress_muxfpga_func)
68 : : return -ENXIO;
69 : :
70 : 0 : err = vexpress_config_write(vexpress_muxfpga_func, 0, site);
71 [ # # ]: 0 : if (!err) {
72 : : pr_debug("Selected MUXFPGA input %d (fb%d)\n", site,
73 : : info->node);
74 : 0 : vexpress_dvi_fb = info->node;
75 : 0 : vexpress_dvi_mode_set(info, info->var.xres,
76 : : info->var.yres);
77 : : } else {
78 : 0 : pr_warn("Failed to select MUXFPGA input %d (fb%d)! (%d)\n",
79 : : site, info->node, err);
80 : : }
81 : :
82 : 0 : return err;
83 : : }
84 : :
85 : 0 : static int vexpress_dvi_fb_select(int fb)
86 : : {
87 : : int err;
88 : : struct fb_info *info;
89 : :
90 : : /* fb0 is the default */
91 [ # # ]: 0 : if (fb < 0)
92 : : fb = 0;
93 : :
94 : 0 : info = registered_fb[fb];
95 [ # # ][ # # ]: 0 : if (!info || !lock_fb_info(info))
96 : : return -ENODEV;
97 : :
98 : 0 : err = vexpress_dvi_mux_set(info);
99 : :
100 : : unlock_fb_info(info);
101 : :
102 : 0 : return err;
103 : : }
104 : :
105 : 0 : static ssize_t vexpress_dvi_fb_show(struct device *dev,
106 : : struct device_attribute *attr, char *buf)
107 : : {
108 : 0 : return sprintf(buf, "%d\n", vexpress_dvi_fb);
109 : : }
110 : :
111 : 0 : static ssize_t vexpress_dvi_fb_store(struct device *dev,
112 : : struct device_attribute *attr, const char *buf, size_t count)
113 : : {
114 : : long value;
115 : : int err = kstrtol(buf, 0, &value);
116 : :
117 [ # # ]: 0 : if (!err)
118 : 0 : err = vexpress_dvi_fb_select(value);
119 : :
120 [ # # ]: 0 : return err ? err : count;
121 : : }
122 : :
123 : : DEVICE_ATTR(fb, S_IRUGO | S_IWUSR, vexpress_dvi_fb_show,
124 : : vexpress_dvi_fb_store);
125 : :
126 : :
127 : 0 : static int vexpress_dvi_fb_event_notify(struct notifier_block *self,
128 : : unsigned long action, void *data)
129 : : {
130 : : struct fb_event *event = data;
131 : 0 : struct fb_info *info = event->info;
132 : 0 : struct fb_videomode *mode = event->data;
133 : :
134 [ # # # ]: 0 : switch (action) {
135 : : case FB_EVENT_FB_REGISTERED:
136 [ # # ]: 0 : if (vexpress_dvi_fb < 0)
137 : 0 : vexpress_dvi_mux_set(info);
138 : : break;
139 : : case FB_EVENT_MODE_CHANGE:
140 : : case FB_EVENT_MODE_CHANGE_ALL:
141 [ # # ]: 0 : if (info->node == vexpress_dvi_fb)
142 : 0 : vexpress_dvi_mode_set(info, mode->xres, mode->yres);
143 : : break;
144 : : }
145 : :
146 : 0 : return NOTIFY_OK;
147 : : }
148 : :
149 : : static struct notifier_block vexpress_dvi_fb_notifier = {
150 : : .notifier_call = vexpress_dvi_fb_event_notify,
151 : : };
152 : : static bool vexpress_dvi_fb_notifier_registered;
153 : :
154 : :
155 : : enum vexpress_dvi_func { FUNC_MUXFPGA, FUNC_DVIMODE };
156 : :
157 : : static struct of_device_id vexpress_dvi_of_match[] = {
158 : : {
159 : : .compatible = "arm,vexpress-muxfpga",
160 : : .data = (void *)FUNC_MUXFPGA,
161 : : }, {
162 : : .compatible = "arm,vexpress-dvimode",
163 : : .data = (void *)FUNC_DVIMODE,
164 : : },
165 : : {}
166 : : };
167 : :
168 : 0 : static int vexpress_dvi_probe(struct platform_device *pdev)
169 : : {
170 : : enum vexpress_dvi_func func;
171 : 0 : const struct of_device_id *match =
172 : 0 : of_match_device(vexpress_dvi_of_match, &pdev->dev);
173 : :
174 [ # # ]: 0 : if (match)
175 : 0 : func = (enum vexpress_dvi_func)match->data;
176 : : else
177 : 0 : func = pdev->id_entry->driver_data;
178 : :
179 [ # # # ]: 0 : switch (func) {
180 : : case FUNC_MUXFPGA:
181 : 0 : vexpress_muxfpga_func =
182 : 0 : vexpress_config_func_get_by_dev(&pdev->dev);
183 : 0 : device_create_file(&pdev->dev, &dev_attr_fb);
184 : 0 : break;
185 : : case FUNC_DVIMODE:
186 : 0 : vexpress_dvimode_func =
187 : 0 : vexpress_config_func_get_by_dev(&pdev->dev);
188 : 0 : break;
189 : : }
190 : :
191 [ # # ]: 0 : if (!vexpress_dvi_fb_notifier_registered) {
192 : 0 : fb_register_client(&vexpress_dvi_fb_notifier);
193 : 0 : vexpress_dvi_fb_notifier_registered = true;
194 : : }
195 : :
196 : 0 : vexpress_dvi_fb_select(vexpress_dvi_fb);
197 : :
198 : 0 : return 0;
199 : : }
200 : :
201 : : static const struct platform_device_id vexpress_dvi_id_table[] = {
202 : : { .name = "vexpress-muxfpga", .driver_data = FUNC_MUXFPGA, },
203 : : { .name = "vexpress-dvimode", .driver_data = FUNC_DVIMODE, },
204 : : {}
205 : : };
206 : :
207 : : static struct platform_driver vexpress_dvi_driver = {
208 : : .probe = vexpress_dvi_probe,
209 : : .driver = {
210 : : .name = "vexpress-dvi",
211 : : .of_match_table = vexpress_dvi_of_match,
212 : : },
213 : : .id_table = vexpress_dvi_id_table,
214 : : };
215 : :
216 : 0 : static int __init vexpress_dvi_init(void)
217 : : {
218 : 0 : return platform_driver_register(&vexpress_dvi_driver);
219 : : }
220 : : device_initcall(vexpress_dvi_init);
|