diff options
102 files changed, 6285 insertions, 5469 deletions
diff --git a/Documentation/DocBook/media/v4l/pixfmt-nv24.xml b/Documentation/DocBook/media/v4l/pixfmt-nv24.xml new file mode 100644 index 000000000000..fb255f2ca9dd --- /dev/null +++ b/Documentation/DocBook/media/v4l/pixfmt-nv24.xml | |||
@@ -0,0 +1,121 @@ | |||
1 | <refentry> | ||
2 | <refmeta> | ||
3 | <refentrytitle>V4L2_PIX_FMT_NV24 ('NV24'), V4L2_PIX_FMT_NV42 ('NV42')</refentrytitle> | ||
4 | &manvol; | ||
5 | </refmeta> | ||
6 | <refnamediv> | ||
7 | <refname id="V4L2-PIX-FMT-NV24"><constant>V4L2_PIX_FMT_NV24</constant></refname> | ||
8 | <refname id="V4L2-PIX-FMT-NV42"><constant>V4L2_PIX_FMT_NV42</constant></refname> | ||
9 | <refpurpose>Formats with full horizontal and vertical | ||
10 | chroma resolutions, also known as YUV 4:4:4. One luminance and one | ||
11 | chrominance plane with alternating chroma samples as opposed to | ||
12 | <constant>V4L2_PIX_FMT_YVU420</constant></refpurpose> | ||
13 | </refnamediv> | ||
14 | <refsect1> | ||
15 | <title>Description</title> | ||
16 | |||
17 | <para>These are two-plane versions of the YUV 4:4:4 format. The three | ||
18 | components are separated into two sub-images or planes. The Y plane is | ||
19 | first, with each Y sample stored in one byte per pixel. For | ||
20 | <constant>V4L2_PIX_FMT_NV24</constant>, a combined CbCr plane | ||
21 | immediately follows the Y plane in memory. The CbCr plane has the same | ||
22 | width and height, in pixels, as the Y plane (and the image). Each line | ||
23 | contains one CbCr pair per pixel, with each Cb and Cr sample stored in | ||
24 | one byte. <constant>V4L2_PIX_FMT_NV42</constant> is the same except that | ||
25 | the Cb and Cr samples are swapped, the CrCb plane starts with a Cr | ||
26 | sample.</para> | ||
27 | |||
28 | <para>If the Y plane has pad bytes after each row, then the CbCr plane | ||
29 | has twice as many pad bytes after its rows.</para> | ||
30 | |||
31 | <example> | ||
32 | <title><constant>V4L2_PIX_FMT_NV24</constant> 4 × 4 | ||
33 | pixel image</title> | ||
34 | |||
35 | <formalpara> | ||
36 | <title>Byte Order.</title> | ||
37 | <para>Each cell is one byte. | ||
38 | <informaltable frame="none"> | ||
39 | <tgroup cols="9" align="center"> | ||
40 | <colspec align="left" colwidth="2*" /> | ||
41 | <tbody valign="top"> | ||
42 | <row> | ||
43 | <entry>start + 0:</entry> | ||
44 | <entry>Y'<subscript>00</subscript></entry> | ||
45 | <entry>Y'<subscript>01</subscript></entry> | ||
46 | <entry>Y'<subscript>02</subscript></entry> | ||
47 | <entry>Y'<subscript>03</subscript></entry> | ||
48 | </row> | ||
49 | <row> | ||
50 | <entry>start + 4:</entry> | ||
51 | <entry>Y'<subscript>10</subscript></entry> | ||
52 | <entry>Y'<subscript>11</subscript></entry> | ||
53 | <entry>Y'<subscript>12</subscript></entry> | ||
54 | <entry>Y'<subscript>13</subscript></entry> | ||
55 | </row> | ||
56 | <row> | ||
57 | <entry>start + 8:</entry> | ||
58 | <entry>Y'<subscript>20</subscript></entry> | ||
59 | <entry>Y'<subscript>21</subscript></entry> | ||
60 | <entry>Y'<subscript>22</subscript></entry> | ||
61 | <entry>Y'<subscript>23</subscript></entry> | ||
62 | </row> | ||
63 | <row> | ||
64 | <entry>start + 12:</entry> | ||
65 | <entry>Y'<subscript>30</subscript></entry> | ||
66 | <entry>Y'<subscript>31</subscript></entry> | ||
67 | <entry>Y'<subscript>32</subscript></entry> | ||
68 | <entry>Y'<subscript>33</subscript></entry> | ||
69 | </row> | ||
70 | <row> | ||
71 | <entry>start + 16:</entry> | ||
72 | <entry>Cb<subscript>00</subscript></entry> | ||
73 | <entry>Cr<subscript>00</subscript></entry> | ||
74 | <entry>Cb<subscript>01</subscript></entry> | ||
75 | <entry>Cr<subscript>01</subscript></entry> | ||
76 | <entry>Cb<subscript>02</subscript></entry> | ||
77 | <entry>Cr<subscript>02</subscript></entry> | ||
78 | <entry>Cb<subscript>03</subscript></entry> | ||
79 | <entry>Cr<subscript>03</subscript></entry> | ||
80 | </row> | ||
81 | <row> | ||
82 | <entry>start + 24:</entry> | ||
83 | <entry>Cb<subscript>10</subscript></entry> | ||
84 | <entry>Cr<subscript>10</subscript></entry> | ||
85 | <entry>Cb<subscript>11</subscript></entry> | ||
86 | <entry>Cr<subscript>11</subscript></entry> | ||
87 | <entry>Cb<subscript>12</subscript></entry> | ||
88 | <entry>Cr<subscript>12</subscript></entry> | ||
89 | <entry>Cb<subscript>13</subscript></entry> | ||
90 | <entry>Cr<subscript>13</subscript></entry> | ||
91 | </row> | ||
92 | <row> | ||
93 | <entry>start + 32:</entry> | ||
94 | <entry>Cb<subscript>20</subscript></entry> | ||
95 | <entry>Cr<subscript>20</subscript></entry> | ||
96 | <entry>Cb<subscript>21</subscript></entry> | ||
97 | <entry>Cr<subscript>21</subscript></entry> | ||
98 | <entry>Cb<subscript>22</subscript></entry> | ||
99 | <entry>Cr<subscript>22</subscript></entry> | ||
100 | <entry>Cb<subscript>23</subscript></entry> | ||
101 | <entry>Cr<subscript>23</subscript></entry> | ||
102 | </row> | ||
103 | <row> | ||
104 | <entry>start + 40:</entry> | ||
105 | <entry>Cb<subscript>30</subscript></entry> | ||
106 | <entry>Cr<subscript>30</subscript></entry> | ||
107 | <entry>Cb<subscript>31</subscript></entry> | ||
108 | <entry>Cr<subscript>31</subscript></entry> | ||
109 | <entry>Cb<subscript>32</subscript></entry> | ||
110 | <entry>Cr<subscript>32</subscript></entry> | ||
111 | <entry>Cb<subscript>33</subscript></entry> | ||
112 | <entry>Cr<subscript>33</subscript></entry> | ||
113 | </row> | ||
114 | </tbody> | ||
115 | </tgroup> | ||
116 | </informaltable> | ||
117 | </para> | ||
118 | </formalpara> | ||
119 | </example> | ||
120 | </refsect1> | ||
121 | </refentry> | ||
diff --git a/Documentation/DocBook/media/v4l/pixfmt.xml b/Documentation/DocBook/media/v4l/pixfmt.xml index 2ff6b7776d7f..aef4615fb07b 100644 --- a/Documentation/DocBook/media/v4l/pixfmt.xml +++ b/Documentation/DocBook/media/v4l/pixfmt.xml | |||
@@ -714,6 +714,7 @@ information.</para> | |||
714 | &sub-nv12m; | 714 | &sub-nv12m; |
715 | &sub-nv12mt; | 715 | &sub-nv12mt; |
716 | &sub-nv16; | 716 | &sub-nv16; |
717 | &sub-nv24; | ||
717 | &sub-m420; | 718 | &sub-m420; |
718 | </section> | 719 | </section> |
719 | 720 | ||
diff --git a/Documentation/fb/api.txt b/Documentation/fb/api.txt new file mode 100644 index 000000000000..d4ff7de85700 --- /dev/null +++ b/Documentation/fb/api.txt | |||
@@ -0,0 +1,306 @@ | |||
1 | The Frame Buffer Device API | ||
2 | --------------------------- | ||
3 | |||
4 | Last revised: June 21, 2011 | ||
5 | |||
6 | |||
7 | 0. Introduction | ||
8 | --------------- | ||
9 | |||
10 | This document describes the frame buffer API used by applications to interact | ||
11 | with frame buffer devices. In-kernel APIs between device drivers and the frame | ||
12 | buffer core are not described. | ||
13 | |||
14 | Due to a lack of documentation in the original frame buffer API, drivers | ||
15 | behaviours differ in subtle (and not so subtle) ways. This document describes | ||
16 | the recommended API implementation, but applications should be prepared to | ||
17 | deal with different behaviours. | ||
18 | |||
19 | |||
20 | 1. Capabilities | ||
21 | --------------- | ||
22 | |||
23 | Device and driver capabilities are reported in the fixed screen information | ||
24 | capabilities field. | ||
25 | |||
26 | struct fb_fix_screeninfo { | ||
27 | ... | ||
28 | __u16 capabilities; /* see FB_CAP_* */ | ||
29 | ... | ||
30 | }; | ||
31 | |||
32 | Application should use those capabilities to find out what features they can | ||
33 | expect from the device and driver. | ||
34 | |||
35 | - FB_CAP_FOURCC | ||
36 | |||
37 | The driver supports the four character code (FOURCC) based format setting API. | ||
38 | When supported, formats are configured using a FOURCC instead of manually | ||
39 | specifying color components layout. | ||
40 | |||
41 | |||
42 | 2. Types and visuals | ||
43 | -------------------- | ||
44 | |||
45 | Pixels are stored in memory in hardware-dependent formats. Applications need | ||
46 | to be aware of the pixel storage format in order to write image data to the | ||
47 | frame buffer memory in the format expected by the hardware. | ||
48 | |||
49 | Formats are described by frame buffer types and visuals. Some visuals require | ||
50 | additional information, which are stored in the variable screen information | ||
51 | bits_per_pixel, grayscale, red, green, blue and transp fields. | ||
52 | |||
53 | Visuals describe how color information is encoded and assembled to create | ||
54 | macropixels. Types describe how macropixels are stored in memory. The following | ||
55 | types and visuals are supported. | ||
56 | |||
57 | - FB_TYPE_PACKED_PIXELS | ||
58 | |||
59 | Macropixels are stored contiguously in a single plane. If the number of bits | ||
60 | per macropixel is not a multiple of 8, whether macropixels are padded to the | ||
61 | next multiple of 8 bits or packed together into bytes depends on the visual. | ||
62 | |||
63 | Padding at end of lines may be present and is then reported through the fixed | ||
64 | screen information line_length field. | ||
65 | |||
66 | - FB_TYPE_PLANES | ||
67 | |||
68 | Macropixels are split across multiple planes. The number of planes is equal to | ||
69 | the number of bits per macropixel, with plane i'th storing i'th bit from all | ||
70 | macropixels. | ||
71 | |||
72 | Planes are located contiguously in memory. | ||
73 | |||
74 | - FB_TYPE_INTERLEAVED_PLANES | ||
75 | |||
76 | Macropixels are split across multiple planes. The number of planes is equal to | ||
77 | the number of bits per macropixel, with plane i'th storing i'th bit from all | ||
78 | macropixels. | ||
79 | |||
80 | Planes are interleaved in memory. The interleave factor, defined as the | ||
81 | distance in bytes between the beginning of two consecutive interleaved blocks | ||
82 | belonging to different planes, is stored in the fixed screen information | ||
83 | type_aux field. | ||
84 | |||
85 | - FB_TYPE_FOURCC | ||
86 | |||
87 | Macropixels are stored in memory as described by the format FOURCC identifier | ||
88 | stored in the variable screen information grayscale field. | ||
89 | |||
90 | - FB_VISUAL_MONO01 | ||
91 | |||
92 | Pixels are black or white and stored on a number of bits (typically one) | ||
93 | specified by the variable screen information bpp field. | ||
94 | |||
95 | Black pixels are represented by all bits set to 1 and white pixels by all bits | ||
96 | set to 0. When the number of bits per pixel is smaller than 8, several pixels | ||
97 | are packed together in a byte. | ||
98 | |||
99 | FB_VISUAL_MONO01 is currently used with FB_TYPE_PACKED_PIXELS only. | ||
100 | |||
101 | - FB_VISUAL_MONO10 | ||
102 | |||
103 | Pixels are black or white and stored on a number of bits (typically one) | ||
104 | specified by the variable screen information bpp field. | ||
105 | |||
106 | Black pixels are represented by all bits set to 0 and white pixels by all bits | ||
107 | set to 1. When the number of bits per pixel is smaller than 8, several pixels | ||
108 | are packed together in a byte. | ||
109 | |||
110 | FB_VISUAL_MONO01 is currently used with FB_TYPE_PACKED_PIXELS only. | ||
111 | |||
112 | - FB_VISUAL_TRUECOLOR | ||
113 | |||
114 | Pixels are broken into red, green and blue components, and each component | ||
115 | indexes a read-only lookup table for the corresponding value. Lookup tables | ||
116 | are device-dependent, and provide linear or non-linear ramps. | ||
117 | |||
118 | Each component is stored in a macropixel according to the variable screen | ||
119 | information red, green, blue and transp fields. | ||
120 | |||
121 | - FB_VISUAL_PSEUDOCOLOR and FB_VISUAL_STATIC_PSEUDOCOLOR | ||
122 | |||
123 | Pixel values are encoded as indices into a colormap that stores red, green and | ||
124 | blue components. The colormap is read-only for FB_VISUAL_STATIC_PSEUDOCOLOR | ||
125 | and read-write for FB_VISUAL_PSEUDOCOLOR. | ||
126 | |||
127 | Each pixel value is stored in the number of bits reported by the variable | ||
128 | screen information bits_per_pixel field. | ||
129 | |||
130 | - FB_VISUAL_DIRECTCOLOR | ||
131 | |||
132 | Pixels are broken into red, green and blue components, and each component | ||
133 | indexes a programmable lookup table for the corresponding value. | ||
134 | |||
135 | Each component is stored in a macropixel according to the variable screen | ||
136 | information red, green, blue and transp fields. | ||
137 | |||
138 | - FB_VISUAL_FOURCC | ||
139 | |||
140 | Pixels are encoded and interpreted as described by the format FOURCC | ||
141 | identifier stored in the variable screen information grayscale field. | ||
142 | |||
143 | |||
144 | 3. Screen information | ||
145 | --------------------- | ||
146 | |||
147 | Screen information are queried by applications using the FBIOGET_FSCREENINFO | ||
148 | and FBIOGET_VSCREENINFO ioctls. Those ioctls take a pointer to a | ||
149 | fb_fix_screeninfo and fb_var_screeninfo structure respectively. | ||
150 | |||
151 | struct fb_fix_screeninfo stores device independent unchangeable information | ||
152 | about the frame buffer device and the current format. Those information can't | ||
153 | be directly modified by applications, but can be changed by the driver when an | ||
154 | application modifies the format. | ||
155 | |||
156 | struct fb_fix_screeninfo { | ||
157 | char id[16]; /* identification string eg "TT Builtin" */ | ||
158 | unsigned long smem_start; /* Start of frame buffer mem */ | ||
159 | /* (physical address) */ | ||
160 | __u32 smem_len; /* Length of frame buffer mem */ | ||
161 | __u32 type; /* see FB_TYPE_* */ | ||
162 | __u32 type_aux; /* Interleave for interleaved Planes */ | ||
163 | __u32 visual; /* see FB_VISUAL_* */ | ||
164 | __u16 xpanstep; /* zero if no hardware panning */ | ||
165 | __u16 ypanstep; /* zero if no hardware panning */ | ||
166 | __u16 ywrapstep; /* zero if no hardware ywrap */ | ||
167 | __u32 line_length; /* length of a line in bytes */ | ||
168 | unsigned long mmio_start; /* Start of Memory Mapped I/O */ | ||
169 | /* (physical address) */ | ||
170 | __u32 mmio_len; /* Length of Memory Mapped I/O */ | ||
171 | __u32 accel; /* Indicate to driver which */ | ||
172 | /* specific chip/card we have */ | ||
173 | __u16 capabilities; /* see FB_CAP_* */ | ||
174 | __u16 reserved[2]; /* Reserved for future compatibility */ | ||
175 | }; | ||
176 | |||
177 | struct fb_var_screeninfo stores device independent changeable information | ||
178 | about a frame buffer device, its current format and video mode, as well as | ||
179 | other miscellaneous parameters. | ||
180 | |||
181 | struct fb_var_screeninfo { | ||
182 | __u32 xres; /* visible resolution */ | ||
183 | __u32 yres; | ||
184 | __u32 xres_virtual; /* virtual resolution */ | ||
185 | __u32 yres_virtual; | ||
186 | __u32 xoffset; /* offset from virtual to visible */ | ||
187 | __u32 yoffset; /* resolution */ | ||
188 | |||
189 | __u32 bits_per_pixel; /* guess what */ | ||
190 | __u32 grayscale; /* 0 = color, 1 = grayscale, */ | ||
191 | /* >1 = FOURCC */ | ||
192 | struct fb_bitfield red; /* bitfield in fb mem if true color, */ | ||
193 | struct fb_bitfield green; /* else only length is significant */ | ||
194 | struct fb_bitfield blue; | ||
195 | struct fb_bitfield transp; /* transparency */ | ||
196 | |||
197 | __u32 nonstd; /* != 0 Non standard pixel format */ | ||
198 | |||
199 | __u32 activate; /* see FB_ACTIVATE_* */ | ||
200 | |||
201 | __u32 height; /* height of picture in mm */ | ||
202 | __u32 width; /* width of picture in mm */ | ||
203 | |||
204 | __u32 accel_flags; /* (OBSOLETE) see fb_info.flags */ | ||
205 | |||
206 | /* Timing: All values in pixclocks, except pixclock (of course) */ | ||
207 | __u32 pixclock; /* pixel clock in ps (pico seconds) */ | ||
208 | __u32 left_margin; /* time from sync to picture */ | ||
209 | __u32 right_margin; /* time from picture to sync */ | ||
210 | __u32 upper_margin; /* time from sync to picture */ | ||
211 | __u32 lower_margin; | ||
212 | __u32 hsync_len; /* length of horizontal sync */ | ||
213 | __u32 vsync_len; /* length of vertical sync */ | ||
214 | __u32 sync; /* see FB_SYNC_* */ | ||
215 | __u32 vmode; /* see FB_VMODE_* */ | ||
216 | __u32 rotate; /* angle we rotate counter clockwise */ | ||
217 | __u32 colorspace; /* colorspace for FOURCC-based modes */ | ||
218 | __u32 reserved[4]; /* Reserved for future compatibility */ | ||
219 | }; | ||
220 | |||
221 | To modify variable information, applications call the FBIOPUT_VSCREENINFO | ||
222 | ioctl with a pointer to a fb_var_screeninfo structure. If the call is | ||
223 | successful, the driver will update the fixed screen information accordingly. | ||
224 | |||
225 | Instead of filling the complete fb_var_screeninfo structure manually, | ||
226 | applications should call the FBIOGET_VSCREENINFO ioctl and modify only the | ||
227 | fields they care about. | ||
228 | |||
229 | |||
230 | 4. Format configuration | ||
231 | ----------------------- | ||
232 | |||
233 | Frame buffer devices offer two ways to configure the frame buffer format: the | ||
234 | legacy API and the FOURCC-based API. | ||
235 | |||
236 | |||
237 | The legacy API has been the only frame buffer format configuration API for a | ||
238 | long time and is thus widely used by application. It is the recommended API | ||
239 | for applications when using RGB and grayscale formats, as well as legacy | ||
240 | non-standard formats. | ||
241 | |||
242 | To select a format, applications set the fb_var_screeninfo bits_per_pixel field | ||
243 | to the desired frame buffer depth. Values up to 8 will usually map to | ||
244 | monochrome, grayscale or pseudocolor visuals, although this is not required. | ||
245 | |||
246 | - For grayscale formats, applications set the grayscale field to one. The red, | ||
247 | blue, green and transp fields must be set to 0 by applications and ignored by | ||
248 | drivers. Drivers must fill the red, blue and green offsets to 0 and lengths | ||
249 | to the bits_per_pixel value. | ||
250 | |||
251 | - For pseudocolor formats, applications set the grayscale field to zero. The | ||
252 | red, blue, green and transp fields must be set to 0 by applications and | ||
253 | ignored by drivers. Drivers must fill the red, blue and green offsets to 0 | ||
254 | and lengths to the bits_per_pixel value. | ||
255 | |||
256 | - For truecolor and directcolor formats, applications set the grayscale field | ||
257 | to zero, and the red, blue, green and transp fields to describe the layout of | ||
258 | color components in memory. | ||
259 | |||
260 | struct fb_bitfield { | ||
261 | __u32 offset; /* beginning of bitfield */ | ||
262 | __u32 length; /* length of bitfield */ | ||
263 | __u32 msb_right; /* != 0 : Most significant bit is */ | ||
264 | /* right */ | ||
265 | }; | ||
266 | |||
267 | Pixel values are bits_per_pixel wide and are split in non-overlapping red, | ||
268 | green, blue and alpha (transparency) components. Location and size of each | ||
269 | component in the pixel value are described by the fb_bitfield offset and | ||
270 | length fields. Offset are computed from the right. | ||
271 | |||
272 | Pixels are always stored in an integer number of bytes. If the number of | ||
273 | bits per pixel is not a multiple of 8, pixel values are padded to the next | ||
274 | multiple of 8 bits. | ||
275 | |||
276 | Upon successful format configuration, drivers update the fb_fix_screeninfo | ||
277 | type, visual and line_length fields depending on the selected format. | ||
278 | |||
279 | |||
280 | The FOURCC-based API replaces format descriptions by four character codes | ||
281 | (FOURCC). FOURCCs are abstract identifiers that uniquely define a format | ||
282 | without explicitly describing it. This is the only API that supports YUV | ||
283 | formats. Drivers are also encouraged to implement the FOURCC-based API for RGB | ||
284 | and grayscale formats. | ||
285 | |||
286 | Drivers that support the FOURCC-based API report this capability by setting | ||
287 | the FB_CAP_FOURCC bit in the fb_fix_screeninfo capabilities field. | ||
288 | |||
289 | FOURCC definitions are located in the linux/videodev2.h header. However, and | ||
290 | despite starting with the V4L2_PIX_FMT_prefix, they are not restricted to V4L2 | ||
291 | and don't require usage of the V4L2 subsystem. FOURCC documentation is | ||
292 | available in Documentation/DocBook/v4l/pixfmt.xml. | ||
293 | |||
294 | To select a format, applications set the grayscale field to the desired FOURCC. | ||
295 | For YUV formats, they should also select the appropriate colorspace by setting | ||
296 | the colorspace field to one of the colorspaces listed in linux/videodev2.h and | ||
297 | documented in Documentation/DocBook/v4l/colorspaces.xml. | ||
298 | |||
299 | The red, green, blue and transp fields are not used with the FOURCC-based API. | ||
300 | For forward compatibility reasons applications must zero those fields, and | ||
301 | drivers must ignore them. Values other than 0 may get a meaning in future | ||
302 | extensions. | ||
303 | |||
304 | Upon successful format configuration, drivers update the fb_fix_screeninfo | ||
305 | type, visual and line_length fields depending on the selected format. The type | ||
306 | and visual fields are set to FB_TYPE_FOURCC and FB_VISUAL_FOURCC respectively. | ||
diff --git a/MAINTAINERS b/MAINTAINERS index 4d1ba2022a95..ebbee877330f 100644 --- a/MAINTAINERS +++ b/MAINTAINERS | |||
@@ -5669,6 +5669,12 @@ L: alsa-devel@alsa-project.org (moderated for non-subscribers) | |||
5669 | S: Supported | 5669 | S: Supported |
5670 | F: sound/soc/samsung | 5670 | F: sound/soc/samsung |
5671 | 5671 | ||
5672 | SAMSUNG FRAMEBUFFER DRIVER | ||
5673 | M: Jingoo Han <jg1.han@samsung.com> | ||
5674 | L: linux-fbdev@vger.kernel.org | ||
5675 | S: Maintained | ||
5676 | F: drivers/video/s3c-fb.c | ||
5677 | |||
5672 | SERIAL DRIVERS | 5678 | SERIAL DRIVERS |
5673 | M: Alan Cox <alan@linux.intel.com> | 5679 | M: Alan Cox <alan@linux.intel.com> |
5674 | L: linux-serial@vger.kernel.org | 5680 | L: linux-serial@vger.kernel.org |
diff --git a/arch/arm/mach-omap2/board-4430sdp.c b/arch/arm/mach-omap2/board-4430sdp.c index 2ceb75d21eb2..39fba9df17fb 100644 --- a/arch/arm/mach-omap2/board-4430sdp.c +++ b/arch/arm/mach-omap2/board-4430sdp.c | |||
@@ -602,20 +602,6 @@ static void __init omap_sfh7741prox_init(void) | |||
602 | __func__, OMAP4_SFH7741_ENABLE_GPIO, error); | 602 | __func__, OMAP4_SFH7741_ENABLE_GPIO, error); |
603 | } | 603 | } |
604 | 604 | ||
605 | static void sdp4430_hdmi_mux_init(void) | ||
606 | { | ||
607 | /* PAD0_HDMI_HPD_PAD1_HDMI_CEC */ | ||
608 | omap_mux_init_signal("hdmi_hpd", | ||
609 | OMAP_PIN_INPUT_PULLUP); | ||
610 | omap_mux_init_signal("hdmi_cec", | ||
611 | OMAP_PIN_INPUT_PULLUP); | ||
612 | /* PAD0_HDMI_DDC_SCL_PAD1_HDMI_DDC_SDA */ | ||
613 | omap_mux_init_signal("hdmi_ddc_scl", | ||
614 | OMAP_PIN_INPUT_PULLUP); | ||
615 | omap_mux_init_signal("hdmi_ddc_sda", | ||
616 | OMAP_PIN_INPUT_PULLUP); | ||
617 | } | ||
618 | |||
619 | static struct gpio sdp4430_hdmi_gpios[] = { | 605 | static struct gpio sdp4430_hdmi_gpios[] = { |
620 | { HDMI_GPIO_HPD, GPIOF_OUT_INIT_HIGH, "hdmi_gpio_hpd" }, | 606 | { HDMI_GPIO_HPD, GPIOF_OUT_INIT_HIGH, "hdmi_gpio_hpd" }, |
621 | { HDMI_GPIO_LS_OE, GPIOF_OUT_INIT_HIGH, "hdmi_gpio_ls_oe" }, | 607 | { HDMI_GPIO_LS_OE, GPIOF_OUT_INIT_HIGH, "hdmi_gpio_ls_oe" }, |
@@ -833,9 +819,16 @@ static void omap_4430sdp_display_init(void) | |||
833 | pr_err("%s: Could not get display_sel GPIO\n", __func__); | 819 | pr_err("%s: Could not get display_sel GPIO\n", __func__); |
834 | 820 | ||
835 | sdp4430_lcd_init(); | 821 | sdp4430_lcd_init(); |
836 | sdp4430_hdmi_mux_init(); | ||
837 | sdp4430_picodlp_init(); | 822 | sdp4430_picodlp_init(); |
838 | omap_display_init(&sdp4430_dss_data); | 823 | omap_display_init(&sdp4430_dss_data); |
824 | /* | ||
825 | * OMAP4460SDP/Blaze and OMAP4430 ES2.3 SDP/Blaze boards and | ||
826 | * later have external pull up on the HDMI I2C lines | ||
827 | */ | ||
828 | if (cpu_is_omap446x() || omap_rev() > OMAP4430_REV_ES2_2) | ||
829 | omap_hdmi_init(OMAP_HDMI_SDA_SCL_EXTERNAL_PULLUP); | ||
830 | else | ||
831 | omap_hdmi_init(0); | ||
839 | } | 832 | } |
840 | 833 | ||
841 | #ifdef CONFIG_OMAP_MUX | 834 | #ifdef CONFIG_OMAP_MUX |
diff --git a/arch/arm/mach-omap2/board-omap4panda.c b/arch/arm/mach-omap2/board-omap4panda.c index e96a2e7ad36f..30ad40db2cf3 100644 --- a/arch/arm/mach-omap2/board-omap4panda.c +++ b/arch/arm/mach-omap2/board-omap4panda.c | |||
@@ -412,21 +412,6 @@ int __init omap4_panda_dvi_init(void) | |||
412 | return r; | 412 | return r; |
413 | } | 413 | } |
414 | 414 | ||
415 | |||
416 | static void omap4_panda_hdmi_mux_init(void) | ||
417 | { | ||
418 | /* PAD0_HDMI_HPD_PAD1_HDMI_CEC */ | ||
419 | omap_mux_init_signal("hdmi_hpd", | ||
420 | OMAP_PIN_INPUT_PULLUP); | ||
421 | omap_mux_init_signal("hdmi_cec", | ||
422 | OMAP_PIN_INPUT_PULLUP); | ||
423 | /* PAD0_HDMI_DDC_SCL_PAD1_HDMI_DDC_SDA */ | ||
424 | omap_mux_init_signal("hdmi_ddc_scl", | ||
425 | OMAP_PIN_INPUT_PULLUP); | ||
426 | omap_mux_init_signal("hdmi_ddc_sda", | ||
427 | OMAP_PIN_INPUT_PULLUP); | ||
428 | } | ||
429 | |||
430 | static struct gpio panda_hdmi_gpios[] = { | 415 | static struct gpio panda_hdmi_gpios[] = { |
431 | { HDMI_GPIO_HPD, GPIOF_OUT_INIT_HIGH, "hdmi_gpio_hpd" }, | 416 | { HDMI_GPIO_HPD, GPIOF_OUT_INIT_HIGH, "hdmi_gpio_hpd" }, |
432 | { HDMI_GPIO_LS_OE, GPIOF_OUT_INIT_HIGH, "hdmi_gpio_ls_oe" }, | 417 | { HDMI_GPIO_LS_OE, GPIOF_OUT_INIT_HIGH, "hdmi_gpio_ls_oe" }, |
@@ -478,8 +463,16 @@ void omap4_panda_display_init(void) | |||
478 | if (r) | 463 | if (r) |
479 | pr_err("error initializing panda DVI\n"); | 464 | pr_err("error initializing panda DVI\n"); |
480 | 465 | ||
481 | omap4_panda_hdmi_mux_init(); | ||
482 | omap_display_init(&omap4_panda_dss_data); | 466 | omap_display_init(&omap4_panda_dss_data); |
467 | |||
468 | /* | ||
469 | * OMAP4460SDP/Blaze and OMAP4430 ES2.3 SDP/Blaze boards and | ||
470 | * later have external pull up on the HDMI I2C lines | ||
471 | */ | ||
472 | if (cpu_is_omap446x() || omap_rev() > OMAP4430_REV_ES2_2) | ||
473 | omap_hdmi_init(OMAP_HDMI_SDA_SCL_EXTERNAL_PULLUP); | ||
474 | else | ||
475 | omap_hdmi_init(0); | ||
483 | } | 476 | } |
484 | 477 | ||
485 | static void __init omap4_panda_init(void) | 478 | static void __init omap4_panda_init(void) |
diff --git a/arch/arm/mach-omap2/display.c b/arch/arm/mach-omap2/display.c index bc6cf863a563..3c446d1a1781 100644 --- a/arch/arm/mach-omap2/display.c +++ b/arch/arm/mach-omap2/display.c | |||
@@ -30,6 +30,7 @@ | |||
30 | #include <plat/omap-pm.h> | 30 | #include <plat/omap-pm.h> |
31 | #include "common.h" | 31 | #include "common.h" |
32 | 32 | ||
33 | #include "mux.h" | ||
33 | #include "control.h" | 34 | #include "control.h" |
34 | #include "display.h" | 35 | #include "display.h" |
35 | 36 | ||
@@ -97,6 +98,36 @@ static const struct omap_dss_hwmod_data omap4_dss_hwmod_data[] __initdata = { | |||
97 | { "dss_hdmi", "omapdss_hdmi", -1 }, | 98 | { "dss_hdmi", "omapdss_hdmi", -1 }, |
98 | }; | 99 | }; |
99 | 100 | ||
101 | static void omap4_hdmi_mux_pads(enum omap_hdmi_flags flags) | ||
102 | { | ||
103 | u32 reg; | ||
104 | u16 control_i2c_1; | ||
105 | |||
106 | /* PAD0_HDMI_HPD_PAD1_HDMI_CEC */ | ||
107 | omap_mux_init_signal("hdmi_hpd", | ||
108 | OMAP_PIN_INPUT_PULLUP); | ||
109 | omap_mux_init_signal("hdmi_cec", | ||
110 | OMAP_PIN_INPUT_PULLUP); | ||
111 | /* PAD0_HDMI_DDC_SCL_PAD1_HDMI_DDC_SDA */ | ||
112 | omap_mux_init_signal("hdmi_ddc_scl", | ||
113 | OMAP_PIN_INPUT_PULLUP); | ||
114 | omap_mux_init_signal("hdmi_ddc_sda", | ||
115 | OMAP_PIN_INPUT_PULLUP); | ||
116 | |||
117 | /* | ||
118 | * CONTROL_I2C_1: HDMI_DDC_SDA_PULLUPRESX (bit 28) and | ||
119 | * HDMI_DDC_SCL_PULLUPRESX (bit 24) are set to disable | ||
120 | * internal pull up resistor. | ||
121 | */ | ||
122 | if (flags & OMAP_HDMI_SDA_SCL_EXTERNAL_PULLUP) { | ||
123 | control_i2c_1 = OMAP4_CTRL_MODULE_PAD_CORE_CONTROL_I2C_1; | ||
124 | reg = omap4_ctrl_pad_readl(control_i2c_1); | ||
125 | reg |= (OMAP4_HDMI_DDC_SDA_PULLUPRESX_MASK | | ||
126 | OMAP4_HDMI_DDC_SCL_PULLUPRESX_MASK); | ||
127 | omap4_ctrl_pad_writel(reg, control_i2c_1); | ||
128 | } | ||
129 | } | ||
130 | |||
100 | static int omap4_dsi_mux_pads(int dsi_id, unsigned lanes) | 131 | static int omap4_dsi_mux_pads(int dsi_id, unsigned lanes) |
101 | { | 132 | { |
102 | u32 enable_mask, enable_shift; | 133 | u32 enable_mask, enable_shift; |
@@ -130,6 +161,14 @@ static int omap4_dsi_mux_pads(int dsi_id, unsigned lanes) | |||
130 | return 0; | 161 | return 0; |
131 | } | 162 | } |
132 | 163 | ||
164 | int omap_hdmi_init(enum omap_hdmi_flags flags) | ||
165 | { | ||
166 | if (cpu_is_omap44xx()) | ||
167 | omap4_hdmi_mux_pads(flags); | ||
168 | |||
169 | return 0; | ||
170 | } | ||
171 | |||
133 | static int omap_dsi_enable_pads(int dsi_id, unsigned lane_mask) | 172 | static int omap_dsi_enable_pads(int dsi_id, unsigned lane_mask) |
134 | { | 173 | { |
135 | if (cpu_is_omap44xx()) | 174 | if (cpu_is_omap44xx()) |
diff --git a/arch/arm/mach-shmobile/board-ag5evm.c b/arch/arm/mach-shmobile/board-ag5evm.c index a4e6ca04e319..eff8a96c75ee 100644 --- a/arch/arm/mach-shmobile/board-ag5evm.c +++ b/arch/arm/mach-shmobile/board-ag5evm.c | |||
@@ -271,7 +271,7 @@ static struct sh_mobile_lcdc_info lcdc0_info = { | |||
271 | .flags = LCDC_FLAGS_DWPOL, | 271 | .flags = LCDC_FLAGS_DWPOL, |
272 | .lcd_size_cfg.width = 44, | 272 | .lcd_size_cfg.width = 44, |
273 | .lcd_size_cfg.height = 79, | 273 | .lcd_size_cfg.height = 79, |
274 | .bpp = 16, | 274 | .fourcc = V4L2_PIX_FMT_RGB565, |
275 | .lcd_cfg = lcdc0_modes, | 275 | .lcd_cfg = lcdc0_modes, |
276 | .num_cfg = ARRAY_SIZE(lcdc0_modes), | 276 | .num_cfg = ARRAY_SIZE(lcdc0_modes), |
277 | .board_cfg = { | 277 | .board_cfg = { |
@@ -321,12 +321,46 @@ static struct resource mipidsi0_resources[] = { | |||
321 | }, | 321 | }, |
322 | }; | 322 | }; |
323 | 323 | ||
324 | #define DSI0PHYCR 0xe615006c | ||
325 | static int sh_mipi_set_dot_clock(struct platform_device *pdev, | ||
326 | void __iomem *base, | ||
327 | int enable) | ||
328 | { | ||
329 | struct clk *pck; | ||
330 | int ret; | ||
331 | |||
332 | pck = clk_get(&pdev->dev, "dsip_clk"); | ||
333 | if (IS_ERR(pck)) { | ||
334 | ret = PTR_ERR(pck); | ||
335 | goto sh_mipi_set_dot_clock_pck_err; | ||
336 | } | ||
337 | |||
338 | if (enable) { | ||
339 | clk_set_rate(pck, clk_round_rate(pck, 24000000)); | ||
340 | __raw_writel(0x2a809010, DSI0PHYCR); | ||
341 | clk_enable(pck); | ||
342 | } else { | ||
343 | clk_disable(pck); | ||
344 | } | ||
345 | |||
346 | ret = 0; | ||
347 | |||
348 | clk_put(pck); | ||
349 | |||
350 | sh_mipi_set_dot_clock_pck_err: | ||
351 | return ret; | ||
352 | } | ||
353 | |||
324 | static struct sh_mipi_dsi_info mipidsi0_info = { | 354 | static struct sh_mipi_dsi_info mipidsi0_info = { |
325 | .data_format = MIPI_RGB888, | 355 | .data_format = MIPI_RGB888, |
326 | .lcd_chan = &lcdc0_info.ch[0], | 356 | .lcd_chan = &lcdc0_info.ch[0], |
357 | .lane = 2, | ||
327 | .vsynw_offset = 20, | 358 | .vsynw_offset = 20, |
328 | .clksrc = 1, | 359 | .clksrc = 1, |
329 | .flags = SH_MIPI_DSI_HSABM, | 360 | .flags = SH_MIPI_DSI_HSABM | |
361 | SH_MIPI_DSI_SYNC_PULSES_MODE | | ||
362 | SH_MIPI_DSI_HSbyteCLK, | ||
363 | .set_dot_clock = sh_mipi_set_dot_clock, | ||
330 | }; | 364 | }; |
331 | 365 | ||
332 | static struct platform_device mipidsi0_device = { | 366 | static struct platform_device mipidsi0_device = { |
@@ -472,8 +506,6 @@ static void __init ag5evm_map_io(void) | |||
472 | shmobile_setup_console(); | 506 | shmobile_setup_console(); |
473 | } | 507 | } |
474 | 508 | ||
475 | #define DSI0PHYCR 0xe615006c | ||
476 | |||
477 | static void __init ag5evm_init(void) | 509 | static void __init ag5evm_init(void) |
478 | { | 510 | { |
479 | sh73a0_pinmux_init(); | 511 | sh73a0_pinmux_init(); |
@@ -554,9 +586,6 @@ static void __init ag5evm_init(void) | |||
554 | gpio_direction_output(GPIO_PORT235, 0); | 586 | gpio_direction_output(GPIO_PORT235, 0); |
555 | lcd_backlight_reset(); | 587 | lcd_backlight_reset(); |
556 | 588 | ||
557 | /* MIPI-DSI clock setup */ | ||
558 | __raw_writel(0x2a809010, DSI0PHYCR); | ||
559 | |||
560 | /* enable SDHI0 on CN15 [SD I/F] */ | 589 | /* enable SDHI0 on CN15 [SD I/F] */ |
561 | gpio_request(GPIO_FN_SDHICD0, NULL); | 590 | gpio_request(GPIO_FN_SDHICD0, NULL); |
562 | gpio_request(GPIO_FN_SDHIWP0, NULL); | 591 | gpio_request(GPIO_FN_SDHIWP0, NULL); |
diff --git a/arch/arm/mach-shmobile/board-ap4evb.c b/arch/arm/mach-shmobile/board-ap4evb.c index d2e7b73aa9b6..aab0a349f759 100644 --- a/arch/arm/mach-shmobile/board-ap4evb.c +++ b/arch/arm/mach-shmobile/board-ap4evb.c | |||
@@ -491,7 +491,7 @@ static struct sh_mobile_lcdc_info lcdc_info = { | |||
491 | .meram_dev = &meram_info, | 491 | .meram_dev = &meram_info, |
492 | .ch[0] = { | 492 | .ch[0] = { |
493 | .chan = LCDC_CHAN_MAINLCD, | 493 | .chan = LCDC_CHAN_MAINLCD, |
494 | .bpp = 16, | 494 | .fourcc = V4L2_PIX_FMT_RGB565, |
495 | .lcd_cfg = ap4evb_lcdc_modes, | 495 | .lcd_cfg = ap4evb_lcdc_modes, |
496 | .num_cfg = ARRAY_SIZE(ap4evb_lcdc_modes), | 496 | .num_cfg = ARRAY_SIZE(ap4evb_lcdc_modes), |
497 | .meram_cfg = &lcd_meram_cfg, | 497 | .meram_cfg = &lcd_meram_cfg, |
@@ -564,6 +564,30 @@ static struct platform_device keysc_device = { | |||
564 | }; | 564 | }; |
565 | 565 | ||
566 | /* MIPI-DSI */ | 566 | /* MIPI-DSI */ |
567 | #define PHYCTRL 0x0070 | ||
568 | static int sh_mipi_set_dot_clock(struct platform_device *pdev, | ||
569 | void __iomem *base, | ||
570 | int enable) | ||
571 | { | ||
572 | struct clk *pck = clk_get(&pdev->dev, "dsip_clk"); | ||
573 | void __iomem *phy = base + PHYCTRL; | ||
574 | |||
575 | if (IS_ERR(pck)) | ||
576 | return PTR_ERR(pck); | ||
577 | |||
578 | if (enable) { | ||
579 | clk_set_rate(pck, clk_round_rate(pck, 24000000)); | ||
580 | iowrite32(ioread32(phy) | (0xb << 8), phy); | ||
581 | clk_enable(pck); | ||
582 | } else { | ||
583 | clk_disable(pck); | ||
584 | } | ||
585 | |||
586 | clk_put(pck); | ||
587 | |||
588 | return 0; | ||
589 | } | ||
590 | |||
567 | static struct resource mipidsi0_resources[] = { | 591 | static struct resource mipidsi0_resources[] = { |
568 | [0] = { | 592 | [0] = { |
569 | .start = 0xffc60000, | 593 | .start = 0xffc60000, |
@@ -580,7 +604,11 @@ static struct resource mipidsi0_resources[] = { | |||
580 | static struct sh_mipi_dsi_info mipidsi0_info = { | 604 | static struct sh_mipi_dsi_info mipidsi0_info = { |
581 | .data_format = MIPI_RGB888, | 605 | .data_format = MIPI_RGB888, |
582 | .lcd_chan = &lcdc_info.ch[0], | 606 | .lcd_chan = &lcdc_info.ch[0], |
607 | .lane = 2, | ||
583 | .vsynw_offset = 17, | 608 | .vsynw_offset = 17, |
609 | .flags = SH_MIPI_DSI_SYNC_PULSES_MODE | | ||
610 | SH_MIPI_DSI_HSbyteCLK, | ||
611 | .set_dot_clock = sh_mipi_set_dot_clock, | ||
584 | }; | 612 | }; |
585 | 613 | ||
586 | static struct platform_device mipidsi0_device = { | 614 | static struct platform_device mipidsi0_device = { |
@@ -798,7 +826,7 @@ static struct sh_mobile_lcdc_info sh_mobile_lcdc1_info = { | |||
798 | .meram_dev = &meram_info, | 826 | .meram_dev = &meram_info, |
799 | .ch[0] = { | 827 | .ch[0] = { |
800 | .chan = LCDC_CHAN_MAINLCD, | 828 | .chan = LCDC_CHAN_MAINLCD, |
801 | .bpp = 16, | 829 | .fourcc = V4L2_PIX_FMT_RGB565, |
802 | .interface_type = RGB24, | 830 | .interface_type = RGB24, |
803 | .clock_divider = 1, | 831 | .clock_divider = 1, |
804 | .flags = LCDC_FLAGS_DWPOL, | 832 | .flags = LCDC_FLAGS_DWPOL, |
diff --git a/arch/arm/mach-shmobile/board-mackerel.c b/arch/arm/mach-shmobile/board-mackerel.c index cbc5934ae03f..9b42fbd10f8e 100644 --- a/arch/arm/mach-shmobile/board-mackerel.c +++ b/arch/arm/mach-shmobile/board-mackerel.c | |||
@@ -388,7 +388,7 @@ static struct sh_mobile_lcdc_info lcdc_info = { | |||
388 | .clock_source = LCDC_CLK_BUS, | 388 | .clock_source = LCDC_CLK_BUS, |
389 | .ch[0] = { | 389 | .ch[0] = { |
390 | .chan = LCDC_CHAN_MAINLCD, | 390 | .chan = LCDC_CHAN_MAINLCD, |
391 | .bpp = 16, | 391 | .fourcc = V4L2_PIX_FMT_RGB565, |
392 | .lcd_cfg = mackerel_lcdc_modes, | 392 | .lcd_cfg = mackerel_lcdc_modes, |
393 | .num_cfg = ARRAY_SIZE(mackerel_lcdc_modes), | 393 | .num_cfg = ARRAY_SIZE(mackerel_lcdc_modes), |
394 | .interface_type = RGB24, | 394 | .interface_type = RGB24, |
@@ -451,7 +451,7 @@ static struct sh_mobile_lcdc_info hdmi_lcdc_info = { | |||
451 | .clock_source = LCDC_CLK_EXTERNAL, | 451 | .clock_source = LCDC_CLK_EXTERNAL, |
452 | .ch[0] = { | 452 | .ch[0] = { |
453 | .chan = LCDC_CHAN_MAINLCD, | 453 | .chan = LCDC_CHAN_MAINLCD, |
454 | .bpp = 16, | 454 | .fourcc = V4L2_PIX_FMT_RGB565, |
455 | .interface_type = RGB24, | 455 | .interface_type = RGB24, |
456 | .clock_divider = 1, | 456 | .clock_divider = 1, |
457 | .flags = LCDC_FLAGS_DWPOL, | 457 | .flags = LCDC_FLAGS_DWPOL, |
diff --git a/arch/arm/mach-shmobile/clock-sh7372.c b/arch/arm/mach-shmobile/clock-sh7372.c index e349c22a0d71..293456d8dcfd 100644 --- a/arch/arm/mach-shmobile/clock-sh7372.c +++ b/arch/arm/mach-shmobile/clock-sh7372.c | |||
@@ -612,8 +612,8 @@ static struct clk_lookup lookups[] = { | |||
612 | CLKDEV_CON_ID("hdmi_clk", &div6_reparent_clks[DIV6_HDMI]), | 612 | CLKDEV_CON_ID("hdmi_clk", &div6_reparent_clks[DIV6_HDMI]), |
613 | CLKDEV_ICK_ID("dsit_clk", "sh-mipi-dsi.0", &div6_clks[DIV6_DSIT]), | 613 | CLKDEV_ICK_ID("dsit_clk", "sh-mipi-dsi.0", &div6_clks[DIV6_DSIT]), |
614 | CLKDEV_ICK_ID("dsit_clk", "sh-mipi-dsi.1", &div6_clks[DIV6_DSIT]), | 614 | CLKDEV_ICK_ID("dsit_clk", "sh-mipi-dsi.1", &div6_clks[DIV6_DSIT]), |
615 | CLKDEV_ICK_ID("dsi0p_clk", "sh-mipi-dsi.0", &div6_clks[DIV6_DSI0P]), | 615 | CLKDEV_ICK_ID("dsip_clk", "sh-mipi-dsi.0", &div6_clks[DIV6_DSI0P]), |
616 | CLKDEV_ICK_ID("dsi1p_clk", "sh-mipi-dsi.1", &div6_clks[DIV6_DSI1P]), | 616 | CLKDEV_ICK_ID("dsip_clk", "sh-mipi-dsi.1", &div6_clks[DIV6_DSI1P]), |
617 | 617 | ||
618 | /* MSTP32 clocks */ | 618 | /* MSTP32 clocks */ |
619 | CLKDEV_DEV_ID("i2c-sh_mobile.2", &mstp_clks[MSTP001]), /* IIC2 */ | 619 | CLKDEV_DEV_ID("i2c-sh_mobile.2", &mstp_clks[MSTP001]), /* IIC2 */ |
diff --git a/arch/arm/mach-shmobile/clock-sh73a0.c b/arch/arm/mach-shmobile/clock-sh73a0.c index 34944d01bf1e..afbead6a6e17 100644 --- a/arch/arm/mach-shmobile/clock-sh73a0.c +++ b/arch/arm/mach-shmobile/clock-sh73a0.c | |||
@@ -427,8 +427,8 @@ static struct clk_lookup lookups[] = { | |||
427 | CLKDEV_CON_ID("sdhi2_clk", &div6_clks[DIV6_SDHI2]), | 427 | CLKDEV_CON_ID("sdhi2_clk", &div6_clks[DIV6_SDHI2]), |
428 | CLKDEV_ICK_ID("dsit_clk", "sh-mipi-dsi.0", &div6_clks[DIV6_DSIT]), | 428 | CLKDEV_ICK_ID("dsit_clk", "sh-mipi-dsi.0", &div6_clks[DIV6_DSIT]), |
429 | CLKDEV_ICK_ID("dsit_clk", "sh-mipi-dsi.1", &div6_clks[DIV6_DSIT]), | 429 | CLKDEV_ICK_ID("dsit_clk", "sh-mipi-dsi.1", &div6_clks[DIV6_DSIT]), |
430 | CLKDEV_ICK_ID("dsi0p_clk", "sh-mipi-dsi.0", &div6_clks[DIV6_DSI0P]), | 430 | CLKDEV_ICK_ID("dsip_clk", "sh-mipi-dsi.0", &div6_clks[DIV6_DSI0P]), |
431 | CLKDEV_ICK_ID("dsi1p_clk", "sh-mipi-dsi.1", &div6_clks[DIV6_DSI1P]), | 431 | CLKDEV_ICK_ID("dsip_clk", "sh-mipi-dsi.1", &div6_clks[DIV6_DSI1P]), |
432 | 432 | ||
433 | /* MSTP32 clocks */ | 433 | /* MSTP32 clocks */ |
434 | CLKDEV_DEV_ID("i2c-sh_mobile.2", &mstp_clks[MSTP001]), /* I2C2 */ | 434 | CLKDEV_DEV_ID("i2c-sh_mobile.2", &mstp_clks[MSTP001]), /* I2C2 */ |
diff --git a/arch/sh/boards/mach-ap325rxa/setup.c b/arch/sh/boards/mach-ap325rxa/setup.c index 74d49c01783b..6418e95c2b6b 100644 --- a/arch/sh/boards/mach-ap325rxa/setup.c +++ b/arch/sh/boards/mach-ap325rxa/setup.c | |||
@@ -207,7 +207,7 @@ static struct sh_mobile_lcdc_info lcdc_info = { | |||
207 | .clock_source = LCDC_CLK_EXTERNAL, | 207 | .clock_source = LCDC_CLK_EXTERNAL, |
208 | .ch[0] = { | 208 | .ch[0] = { |
209 | .chan = LCDC_CHAN_MAINLCD, | 209 | .chan = LCDC_CHAN_MAINLCD, |
210 | .bpp = 16, | 210 | .fourcc = V4L2_PIX_FMT_RGB565, |
211 | .interface_type = RGB18, | 211 | .interface_type = RGB18, |
212 | .clock_divider = 1, | 212 | .clock_divider = 1, |
213 | .lcd_cfg = ap325rxa_lcdc_modes, | 213 | .lcd_cfg = ap325rxa_lcdc_modes, |
diff --git a/arch/sh/boards/mach-ecovec24/setup.c b/arch/sh/boards/mach-ecovec24/setup.c index 9a19fb07276c..033ef2ba621f 100644 --- a/arch/sh/boards/mach-ecovec24/setup.c +++ b/arch/sh/boards/mach-ecovec24/setup.c | |||
@@ -324,7 +324,7 @@ static struct sh_mobile_lcdc_info lcdc_info = { | |||
324 | .ch[0] = { | 324 | .ch[0] = { |
325 | .interface_type = RGB18, | 325 | .interface_type = RGB18, |
326 | .chan = LCDC_CHAN_MAINLCD, | 326 | .chan = LCDC_CHAN_MAINLCD, |
327 | .bpp = 16, | 327 | .fourcc = V4L2_PIX_FMT_RGB565, |
328 | .lcd_size_cfg = { /* 7.0 inch */ | 328 | .lcd_size_cfg = { /* 7.0 inch */ |
329 | .width = 152, | 329 | .width = 152, |
330 | .height = 91, | 330 | .height = 91, |
diff --git a/arch/sh/boards/mach-kfr2r09/setup.c b/arch/sh/boards/mach-kfr2r09/setup.c index 5c3c71366848..2a18b06abdaf 100644 --- a/arch/sh/boards/mach-kfr2r09/setup.c +++ b/arch/sh/boards/mach-kfr2r09/setup.c | |||
@@ -143,7 +143,7 @@ static struct sh_mobile_lcdc_info kfr2r09_sh_lcdc_info = { | |||
143 | .clock_source = LCDC_CLK_BUS, | 143 | .clock_source = LCDC_CLK_BUS, |
144 | .ch[0] = { | 144 | .ch[0] = { |
145 | .chan = LCDC_CHAN_MAINLCD, | 145 | .chan = LCDC_CHAN_MAINLCD, |
146 | .bpp = 16, | 146 | .fourcc = V4L2_PIX_FMT_RGB565, |
147 | .interface_type = SYS18, | 147 | .interface_type = SYS18, |
148 | .clock_divider = 6, | 148 | .clock_divider = 6, |
149 | .flags = LCDC_FLAGS_DWPOL, | 149 | .flags = LCDC_FLAGS_DWPOL, |
diff --git a/arch/sh/boards/mach-migor/setup.c b/arch/sh/boards/mach-migor/setup.c index f8f9377d5684..68c3d6f42896 100644 --- a/arch/sh/boards/mach-migor/setup.c +++ b/arch/sh/boards/mach-migor/setup.c | |||
@@ -241,7 +241,7 @@ static struct sh_mobile_lcdc_info sh_mobile_lcdc_info = { | |||
241 | .clock_source = LCDC_CLK_BUS, | 241 | .clock_source = LCDC_CLK_BUS, |
242 | .ch[0] = { | 242 | .ch[0] = { |
243 | .chan = LCDC_CHAN_MAINLCD, | 243 | .chan = LCDC_CHAN_MAINLCD, |
244 | .bpp = 16, | 244 | .fourcc = V4L2_PIX_FMT_RGB565, |
245 | .interface_type = RGB16, | 245 | .interface_type = RGB16, |
246 | .clock_divider = 2, | 246 | .clock_divider = 2, |
247 | .lcd_cfg = migor_lcd_modes, | 247 | .lcd_cfg = migor_lcd_modes, |
@@ -255,7 +255,7 @@ static struct sh_mobile_lcdc_info sh_mobile_lcdc_info = { | |||
255 | .clock_source = LCDC_CLK_PERIPHERAL, | 255 | .clock_source = LCDC_CLK_PERIPHERAL, |
256 | .ch[0] = { | 256 | .ch[0] = { |
257 | .chan = LCDC_CHAN_MAINLCD, | 257 | .chan = LCDC_CHAN_MAINLCD, |
258 | .bpp = 16, | 258 | .fourcc = V4L2_PIX_FMT_RGB565, |
259 | .interface_type = SYS16A, | 259 | .interface_type = SYS16A, |
260 | .clock_divider = 10, | 260 | .clock_divider = 10, |
261 | .lcd_cfg = migor_lcd_modes, | 261 | .lcd_cfg = migor_lcd_modes, |
diff --git a/arch/sh/boards/mach-se/7724/setup.c b/arch/sh/boards/mach-se/7724/setup.c index 2585733e9bce..036fe1adaef1 100644 --- a/arch/sh/boards/mach-se/7724/setup.c +++ b/arch/sh/boards/mach-se/7724/setup.c | |||
@@ -179,7 +179,7 @@ static struct sh_mobile_lcdc_info lcdc_info = { | |||
179 | .clock_source = LCDC_CLK_EXTERNAL, | 179 | .clock_source = LCDC_CLK_EXTERNAL, |
180 | .ch[0] = { | 180 | .ch[0] = { |
181 | .chan = LCDC_CHAN_MAINLCD, | 181 | .chan = LCDC_CHAN_MAINLCD, |
182 | .bpp = 16, | 182 | .fourcc = V4L2_PIX_FMT_RGB565, |
183 | .clock_divider = 1, | 183 | .clock_divider = 1, |
184 | .lcd_size_cfg = { /* 7.0 inch */ | 184 | .lcd_size_cfg = { /* 7.0 inch */ |
185 | .width = 152, | 185 | .width = 152, |
diff --git a/drivers/media/video/omap/omap_vout.c b/drivers/media/video/omap/omap_vout.c index 0de598bf66bb..a378c2ce1273 100644 --- a/drivers/media/video/omap/omap_vout.c +++ b/drivers/media/video/omap/omap_vout.c | |||
@@ -424,7 +424,7 @@ static int omapvid_setup_overlay(struct omap_vout_device *vout, | |||
424 | "%s enable=%d addr=%x width=%d\n height=%d color_mode=%d\n" | 424 | "%s enable=%d addr=%x width=%d\n height=%d color_mode=%d\n" |
425 | "rotation=%d mirror=%d posx=%d posy=%d out_width = %d \n" | 425 | "rotation=%d mirror=%d posx=%d posy=%d out_width = %d \n" |
426 | "out_height=%d rotation_type=%d screen_width=%d\n", | 426 | "out_height=%d rotation_type=%d screen_width=%d\n", |
427 | __func__, info.enabled, info.paddr, info.width, info.height, | 427 | __func__, ovl->is_enabled(ovl), info.paddr, info.width, info.height, |
428 | info.color_mode, info.rotation, info.mirror, info.pos_x, | 428 | info.color_mode, info.rotation, info.mirror, info.pos_x, |
429 | info.pos_y, info.out_width, info.out_height, info.rotation_type, | 429 | info.pos_y, info.out_width, info.out_height, info.rotation_type, |
430 | info.screen_width); | 430 | info.screen_width); |
@@ -943,12 +943,8 @@ static int omap_vout_release(struct file *file) | |||
943 | /* Disable all the overlay managers connected with this interface */ | 943 | /* Disable all the overlay managers connected with this interface */ |
944 | for (i = 0; i < ovid->num_overlays; i++) { | 944 | for (i = 0; i < ovid->num_overlays; i++) { |
945 | struct omap_overlay *ovl = ovid->overlays[i]; | 945 | struct omap_overlay *ovl = ovid->overlays[i]; |
946 | if (ovl->manager && ovl->manager->device) { | 946 | if (ovl->manager && ovl->manager->device) |
947 | struct omap_overlay_info info; | 947 | ovl->disable(ovl); |
948 | ovl->get_overlay_info(ovl, &info); | ||
949 | info.enabled = 0; | ||
950 | ovl->set_overlay_info(ovl, &info); | ||
951 | } | ||
952 | } | 948 | } |
953 | /* Turn off the pipeline */ | 949 | /* Turn off the pipeline */ |
954 | ret = omapvid_apply_changes(vout); | 950 | ret = omapvid_apply_changes(vout); |
@@ -1668,7 +1664,6 @@ static int vidioc_streamon(struct file *file, void *fh, enum v4l2_buf_type i) | |||
1668 | if (ovl->manager && ovl->manager->device) { | 1664 | if (ovl->manager && ovl->manager->device) { |
1669 | struct omap_overlay_info info; | 1665 | struct omap_overlay_info info; |
1670 | ovl->get_overlay_info(ovl, &info); | 1666 | ovl->get_overlay_info(ovl, &info); |
1671 | info.enabled = 1; | ||
1672 | info.paddr = addr; | 1667 | info.paddr = addr; |
1673 | if (ovl->set_overlay_info(ovl, &info)) { | 1668 | if (ovl->set_overlay_info(ovl, &info)) { |
1674 | ret = -EINVAL; | 1669 | ret = -EINVAL; |
@@ -1687,6 +1682,16 @@ static int vidioc_streamon(struct file *file, void *fh, enum v4l2_buf_type i) | |||
1687 | if (ret) | 1682 | if (ret) |
1688 | v4l2_err(&vout->vid_dev->v4l2_dev, "failed to change mode\n"); | 1683 | v4l2_err(&vout->vid_dev->v4l2_dev, "failed to change mode\n"); |
1689 | 1684 | ||
1685 | for (j = 0; j < ovid->num_overlays; j++) { | ||
1686 | struct omap_overlay *ovl = ovid->overlays[j]; | ||
1687 | |||
1688 | if (ovl->manager && ovl->manager->device) { | ||
1689 | ret = ovl->enable(ovl); | ||
1690 | if (ret) | ||
1691 | goto streamon_err1; | ||
1692 | } | ||
1693 | } | ||
1694 | |||
1690 | ret = 0; | 1695 | ret = 0; |
1691 | 1696 | ||
1692 | streamon_err1: | 1697 | streamon_err1: |
@@ -1716,16 +1721,8 @@ static int vidioc_streamoff(struct file *file, void *fh, enum v4l2_buf_type i) | |||
1716 | for (j = 0; j < ovid->num_overlays; j++) { | 1721 | for (j = 0; j < ovid->num_overlays; j++) { |
1717 | struct omap_overlay *ovl = ovid->overlays[j]; | 1722 | struct omap_overlay *ovl = ovid->overlays[j]; |
1718 | 1723 | ||
1719 | if (ovl->manager && ovl->manager->device) { | 1724 | if (ovl->manager && ovl->manager->device) |
1720 | struct omap_overlay_info info; | 1725 | ovl->disable(ovl); |
1721 | |||
1722 | ovl->get_overlay_info(ovl, &info); | ||
1723 | info.enabled = 0; | ||
1724 | ret = ovl->set_overlay_info(ovl, &info); | ||
1725 | if (ret) | ||
1726 | v4l2_err(&vout->vid_dev->v4l2_dev, | ||
1727 | "failed to update overlay info in streamoff\n"); | ||
1728 | } | ||
1729 | } | 1726 | } |
1730 | 1727 | ||
1731 | /* Turn of the pipeline */ | 1728 | /* Turn of the pipeline */ |
diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig index acd4ba555e3a..6ca0c407c144 100644 --- a/drivers/video/Kconfig +++ b/drivers/video/Kconfig | |||
@@ -2413,7 +2413,6 @@ source "drivers/video/omap/Kconfig" | |||
2413 | source "drivers/video/omap2/Kconfig" | 2413 | source "drivers/video/omap2/Kconfig" |
2414 | 2414 | ||
2415 | source "drivers/video/backlight/Kconfig" | 2415 | source "drivers/video/backlight/Kconfig" |
2416 | source "drivers/video/display/Kconfig" | ||
2417 | 2416 | ||
2418 | if VT | 2417 | if VT |
2419 | source "drivers/video/console/Kconfig" | 2418 | source "drivers/video/console/Kconfig" |
diff --git a/drivers/video/Makefile b/drivers/video/Makefile index 9b9d8fff7732..142606814d98 100644 --- a/drivers/video/Makefile +++ b/drivers/video/Makefile | |||
@@ -13,7 +13,7 @@ fb-objs := $(fb-y) | |||
13 | 13 | ||
14 | obj-$(CONFIG_VT) += console/ | 14 | obj-$(CONFIG_VT) += console/ |
15 | obj-$(CONFIG_LOGO) += logo/ | 15 | obj-$(CONFIG_LOGO) += logo/ |
16 | obj-y += backlight/ display/ | 16 | obj-y += backlight/ |
17 | 17 | ||
18 | obj-$(CONFIG_FB_CFB_FILLRECT) += cfbfillrect.o | 18 | obj-$(CONFIG_FB_CFB_FILLRECT) += cfbfillrect.o |
19 | obj-$(CONFIG_FB_CFB_COPYAREA) += cfbcopyarea.o | 19 | obj-$(CONFIG_FB_CFB_COPYAREA) += cfbcopyarea.o |
diff --git a/drivers/video/amifb.c b/drivers/video/amifb.c index 5ea6596dd824..f23cae094f1b 100644 --- a/drivers/video/amifb.c +++ b/drivers/video/amifb.c | |||
@@ -152,10 +152,10 @@ | |||
152 | 152 | ||
153 | - hsstrt: Start of horizontal synchronization pulse | 153 | - hsstrt: Start of horizontal synchronization pulse |
154 | - hsstop: End of horizontal synchronization pulse | 154 | - hsstop: End of horizontal synchronization pulse |
155 | - htotal: Last value on the line (i.e. line length = htotal+1) | 155 | - htotal: Last value on the line (i.e. line length = htotal + 1) |
156 | - vsstrt: Start of vertical synchronization pulse | 156 | - vsstrt: Start of vertical synchronization pulse |
157 | - vsstop: End of vertical synchronization pulse | 157 | - vsstop: End of vertical synchronization pulse |
158 | - vtotal: Last line value (i.e. number of lines = vtotal+1) | 158 | - vtotal: Last line value (i.e. number of lines = vtotal + 1) |
159 | - hcenter: Start of vertical retrace for interlace | 159 | - hcenter: Start of vertical retrace for interlace |
160 | 160 | ||
161 | You can specify the blanking timings independently. Currently I just set | 161 | You can specify the blanking timings independently. Currently I just set |
@@ -184,7 +184,7 @@ | |||
184 | clock): | 184 | clock): |
185 | 185 | ||
186 | - diwstrt_h: Horizontal start of the visible window | 186 | - diwstrt_h: Horizontal start of the visible window |
187 | - diwstop_h: Horizontal stop+1(*) of the visible window | 187 | - diwstop_h: Horizontal stop + 1(*) of the visible window |
188 | - diwstrt_v: Vertical start of the visible window | 188 | - diwstrt_v: Vertical start of the visible window |
189 | - diwstop_v: Vertical stop of the visible window | 189 | - diwstop_v: Vertical stop of the visible window |
190 | - ddfstrt: Horizontal start of display DMA | 190 | - ddfstrt: Horizontal start of display DMA |
@@ -193,7 +193,7 @@ | |||
193 | 193 | ||
194 | Sprite positioning: | 194 | Sprite positioning: |
195 | 195 | ||
196 | - sprstrt_h: Horizontal start-4 of sprite | 196 | - sprstrt_h: Horizontal start - 4 of sprite |
197 | - sprstrt_v: Vertical start of sprite | 197 | - sprstrt_v: Vertical start of sprite |
198 | 198 | ||
199 | (*) Even Commodore did it wrong in the AGA monitor drivers by not adding 1. | 199 | (*) Even Commodore did it wrong in the AGA monitor drivers by not adding 1. |
@@ -212,21 +212,21 @@ | |||
212 | display parameters. Here's what I found out: | 212 | display parameters. Here's what I found out: |
213 | 213 | ||
214 | - ddfstrt and ddfstop are best aligned to 64 pixels. | 214 | - ddfstrt and ddfstop are best aligned to 64 pixels. |
215 | - the chipset needs 64+4 horizontal pixels after the DMA start before the | 215 | - the chipset needs 64 + 4 horizontal pixels after the DMA start before |
216 | first pixel is output, so diwstrt_h = ddfstrt+64+4 if you want to | 216 | the first pixel is output, so diwstrt_h = ddfstrt + 64 + 4 if you want |
217 | display the first pixel on the line too. Increase diwstrt_h for virtual | 217 | to display the first pixel on the line too. Increase diwstrt_h for |
218 | screen panning. | 218 | virtual screen panning. |
219 | - the display DMA always fetches 64 pixels at a time (fmode = 3). | 219 | - the display DMA always fetches 64 pixels at a time (fmode = 3). |
220 | - ddfstop is ddfstrt+#pixels-64. | 220 | - ddfstop is ddfstrt+#pixels - 64. |
221 | - diwstop_h = diwstrt_h+xres+1. Because of the additional 1 this can be 1 | 221 | - diwstop_h = diwstrt_h + xres + 1. Because of the additional 1 this can |
222 | more than htotal. | 222 | be 1 more than htotal. |
223 | - hscroll simply adds a delay to the display output. Smooth horizontal | 223 | - hscroll simply adds a delay to the display output. Smooth horizontal |
224 | panning needs an extra 64 pixels on the left to prefetch the pixels that | 224 | panning needs an extra 64 pixels on the left to prefetch the pixels that |
225 | `fall off' on the left. | 225 | `fall off' on the left. |
226 | - if ddfstrt < 192, the sprite DMA cycles are all stolen by the bitplane | 226 | - if ddfstrt < 192, the sprite DMA cycles are all stolen by the bitplane |
227 | DMA, so it's best to make the DMA start as late as possible. | 227 | DMA, so it's best to make the DMA start as late as possible. |
228 | - you really don't want to make ddfstrt < 128, since this will steal DMA | 228 | - you really don't want to make ddfstrt < 128, since this will steal DMA |
229 | cycles from the other DMA channels (audio, floppy and Chip RAM refresh). | 229 | cycles from the other DMA channels (audio, floppy and Chip RAM refresh). |
230 | - I make diwstop_h and diwstop_v as large as possible. | 230 | - I make diwstop_h and diwstop_v as large as possible. |
231 | 231 | ||
232 | General dependencies | 232 | General dependencies |
@@ -234,8 +234,8 @@ | |||
234 | 234 | ||
235 | - all values are SHRES pixel (35ns) | 235 | - all values are SHRES pixel (35ns) |
236 | 236 | ||
237 | table 1:fetchstart table 2:prefetch table 3:fetchsize | 237 | table 1:fetchstart table 2:prefetch table 3:fetchsize |
238 | ------------------ ---------------- ----------------- | 238 | ------------------ ---------------- ----------------- |
239 | Pixclock # SHRES|HIRES|LORES # SHRES|HIRES|LORES # SHRES|HIRES|LORES | 239 | Pixclock # SHRES|HIRES|LORES # SHRES|HIRES|LORES # SHRES|HIRES|LORES |
240 | -------------#------+-----+------#------+-----+------#------+-----+------ | 240 | -------------#------+-----+------#------+-----+------#------+-----+------ |
241 | Bus width 1x # 16 | 32 | 64 # 16 | 32 | 64 # 64 | 64 | 64 | 241 | Bus width 1x # 16 | 32 | 64 # 16 | 32 | 64 # 64 | 64 | 64 |
@@ -245,21 +245,21 @@ | |||
245 | - chipset needs 4 pixels before the first pixel is output | 245 | - chipset needs 4 pixels before the first pixel is output |
246 | - ddfstrt must be aligned to fetchstart (table 1) | 246 | - ddfstrt must be aligned to fetchstart (table 1) |
247 | - chipset needs also prefetch (table 2) to get first pixel data, so | 247 | - chipset needs also prefetch (table 2) to get first pixel data, so |
248 | ddfstrt = ((diwstrt_h-4) & -fetchstart) - prefetch | 248 | ddfstrt = ((diwstrt_h - 4) & -fetchstart) - prefetch |
249 | - for horizontal panning decrease diwstrt_h | 249 | - for horizontal panning decrease diwstrt_h |
250 | - the length of a fetchline must be aligned to fetchsize (table 3) | 250 | - the length of a fetchline must be aligned to fetchsize (table 3) |
251 | - if fetchstart is smaller than fetchsize, then ddfstrt can a little bit | 251 | - if fetchstart is smaller than fetchsize, then ddfstrt can a little bit |
252 | moved to optimize use of dma (useful for OCS/ECS overscan displays) | 252 | moved to optimize use of dma (useful for OCS/ECS overscan displays) |
253 | - ddfstop is ddfstrt+ddfsize-fetchsize | 253 | - ddfstop is ddfstrt + ddfsize - fetchsize |
254 | - If C= didn't change anything for AGA, then at following positions the | 254 | - If C= didn't change anything for AGA, then at following positions the |
255 | dma bus is already used: | 255 | dma bus is already used: |
256 | ddfstrt < 48 -> memory refresh | 256 | ddfstrt < 48 -> memory refresh |
257 | < 96 -> disk dma | 257 | < 96 -> disk dma |
258 | < 160 -> audio dma | 258 | < 160 -> audio dma |
259 | < 192 -> sprite 0 dma | 259 | < 192 -> sprite 0 dma |
260 | < 416 -> sprite dma (32 per sprite) | 260 | < 416 -> sprite dma (32 per sprite) |
261 | - in accordance with the hardware reference manual a hardware stop is at | 261 | - in accordance with the hardware reference manual a hardware stop is at |
262 | 192, but AGA (ECS?) can go below this. | 262 | 192, but AGA (ECS?) can go below this. |
263 | 263 | ||
264 | DMA priorities | 264 | DMA priorities |
265 | -------------- | 265 | -------------- |
@@ -269,7 +269,7 @@ | |||
269 | the hardware cursor: | 269 | the hardware cursor: |
270 | 270 | ||
271 | - if you want to start display DMA too early, you lose the ability to | 271 | - if you want to start display DMA too early, you lose the ability to |
272 | do smooth horizontal panning (xpanstep 1 -> 64). | 272 | do smooth horizontal panning (xpanstep 1 -> 64). |
273 | - if you want to go even further, you lose the hardware cursor too. | 273 | - if you want to go even further, you lose the hardware cursor too. |
274 | 274 | ||
275 | IMHO a hardware cursor is more important for X than horizontal scrolling, | 275 | IMHO a hardware cursor is more important for X than horizontal scrolling, |
@@ -286,8 +286,8 @@ | |||
286 | Standard VGA timings | 286 | Standard VGA timings |
287 | -------------------- | 287 | -------------------- |
288 | 288 | ||
289 | xres yres left right upper lower hsync vsync | 289 | xres yres left right upper lower hsync vsync |
290 | ---- ---- ---- ----- ----- ----- ----- ----- | 290 | ---- ---- ---- ----- ----- ----- ----- ----- |
291 | 80x25 720 400 27 45 35 12 108 2 | 291 | 80x25 720 400 27 45 35 12 108 2 |
292 | 80x30 720 480 27 45 30 9 108 2 | 292 | 80x30 720 480 27 45 30 9 108 2 |
293 | 293 | ||
@@ -297,8 +297,8 @@ | |||
297 | 297 | ||
298 | As a comparison, graphics/monitor.h suggests the following: | 298 | As a comparison, graphics/monitor.h suggests the following: |
299 | 299 | ||
300 | xres yres left right upper lower hsync vsync | 300 | xres yres left right upper lower hsync vsync |
301 | ---- ---- ---- ----- ----- ----- ----- ----- | 301 | ---- ---- ---- ----- ----- ----- ----- ----- |
302 | 302 | ||
303 | VGA 640 480 52 112 24 19 112 - 2 + | 303 | VGA 640 480 52 112 24 19 112 - 2 + |
304 | VGA70 640 400 52 112 27 21 112 - 2 - | 304 | VGA70 640 400 52 112 27 21 112 - 2 - |
@@ -309,10 +309,10 @@ | |||
309 | 309 | ||
310 | VSYNC HSYNC Vertical size Vertical total | 310 | VSYNC HSYNC Vertical size Vertical total |
311 | ----- ----- ------------- -------------- | 311 | ----- ----- ------------- -------------- |
312 | + + Reserved Reserved | 312 | + + Reserved Reserved |
313 | + - 400 414 | 313 | + - 400 414 |
314 | - + 350 362 | 314 | - + 350 362 |
315 | - - 480 496 | 315 | - - 480 496 |
316 | 316 | ||
317 | Source: CL-GD542X Technical Reference Manual, Cirrus Logic, Oct 1992 | 317 | Source: CL-GD542X Technical Reference Manual, Cirrus Logic, Oct 1992 |
318 | 318 | ||
@@ -326,33 +326,34 @@ | |||
326 | ----------- | 326 | ----------- |
327 | 327 | ||
328 | - a scanline is 64 µs long, of which 52.48 µs are visible. This is about | 328 | - a scanline is 64 µs long, of which 52.48 µs are visible. This is about |
329 | 736 visible 70 ns pixels per line. | 329 | 736 visible 70 ns pixels per line. |
330 | - we have 625 scanlines, of which 575 are visible (interlaced); after | 330 | - we have 625 scanlines, of which 575 are visible (interlaced); after |
331 | rounding this becomes 576. | 331 | rounding this becomes 576. |
332 | 332 | ||
333 | RETMA -> NTSC | 333 | RETMA -> NTSC |
334 | ------------- | 334 | ------------- |
335 | 335 | ||
336 | - a scanline is 63.5 µs long, of which 53.5 µs are visible. This is about | 336 | - a scanline is 63.5 µs long, of which 53.5 µs are visible. This is about |
337 | 736 visible 70 ns pixels per line. | 337 | 736 visible 70 ns pixels per line. |
338 | - we have 525 scanlines, of which 485 are visible (interlaced); after | 338 | - we have 525 scanlines, of which 485 are visible (interlaced); after |
339 | rounding this becomes 484. | 339 | rounding this becomes 484. |
340 | 340 | ||
341 | Thus if you want a PAL compatible display, you have to do the following: | 341 | Thus if you want a PAL compatible display, you have to do the following: |
342 | 342 | ||
343 | - set the FB_SYNC_BROADCAST flag to indicate that standard broadcast | 343 | - set the FB_SYNC_BROADCAST flag to indicate that standard broadcast |
344 | timings are to be used. | 344 | timings are to be used. |
345 | - make sure upper_margin+yres+lower_margin+vsync_len = 625 for an | 345 | - make sure upper_margin + yres + lower_margin + vsync_len = 625 for an |
346 | interlaced, 312 for a non-interlaced and 156 for a doublescanned | 346 | interlaced, 312 for a non-interlaced and 156 for a doublescanned |
347 | display. | 347 | display. |
348 | - make sure left_margin+xres+right_margin+hsync_len = 1816 for a SHRES, | 348 | - make sure left_margin + xres + right_margin + hsync_len = 1816 for a |
349 | 908 for a HIRES and 454 for a LORES display. | 349 | SHRES, 908 for a HIRES and 454 for a LORES display. |
350 | - the left visible part begins at 360 (SHRES; HIRES:180, LORES:90), | 350 | - the left visible part begins at 360 (SHRES; HIRES:180, LORES:90), |
351 | left_margin+2*hsync_len must be greater or equal. | 351 | left_margin + 2 * hsync_len must be greater or equal. |
352 | - the upper visible part begins at 48 (interlaced; non-interlaced:24, | 352 | - the upper visible part begins at 48 (interlaced; non-interlaced:24, |
353 | doublescanned:12), upper_margin+2*vsync_len must be greater or equal. | 353 | doublescanned:12), upper_margin + 2 * vsync_len must be greater or |
354 | equal. | ||
354 | - ami_encode_var() calculates margins with a hsync of 5320 ns and a vsync | 355 | - ami_encode_var() calculates margins with a hsync of 5320 ns and a vsync |
355 | of 4 scanlines | 356 | of 4 scanlines |
356 | 357 | ||
357 | The settings for a NTSC compatible display are straightforward. | 358 | The settings for a NTSC compatible display are straightforward. |
358 | 359 | ||
@@ -361,7 +362,7 @@ | |||
361 | anything about horizontal/vertical synchronization nor refresh rates. | 362 | anything about horizontal/vertical synchronization nor refresh rates. |
362 | 363 | ||
363 | 364 | ||
364 | -- Geert -- | 365 | -- Geert -- |
365 | 366 | ||
366 | *******************************************************************************/ | 367 | *******************************************************************************/ |
367 | 368 | ||
@@ -540,45 +541,45 @@ static u_short maxfmode, chipset; | |||
540 | * Various macros | 541 | * Various macros |
541 | */ | 542 | */ |
542 | 543 | ||
543 | #define up2(v) (((v)+1) & -2) | 544 | #define up2(v) (((v) + 1) & -2) |
544 | #define down2(v) ((v) & -2) | 545 | #define down2(v) ((v) & -2) |
545 | #define div2(v) ((v)>>1) | 546 | #define div2(v) ((v)>>1) |
546 | #define mod2(v) ((v) & 1) | 547 | #define mod2(v) ((v) & 1) |
547 | 548 | ||
548 | #define up4(v) (((v)+3) & -4) | 549 | #define up4(v) (((v) + 3) & -4) |
549 | #define down4(v) ((v) & -4) | 550 | #define down4(v) ((v) & -4) |
550 | #define mul4(v) ((v)<<2) | 551 | #define mul4(v) ((v) << 2) |
551 | #define div4(v) ((v)>>2) | 552 | #define div4(v) ((v)>>2) |
552 | #define mod4(v) ((v) & 3) | 553 | #define mod4(v) ((v) & 3) |
553 | 554 | ||
554 | #define up8(v) (((v)+7) & -8) | 555 | #define up8(v) (((v) + 7) & -8) |
555 | #define down8(v) ((v) & -8) | 556 | #define down8(v) ((v) & -8) |
556 | #define div8(v) ((v)>>3) | 557 | #define div8(v) ((v)>>3) |
557 | #define mod8(v) ((v) & 7) | 558 | #define mod8(v) ((v) & 7) |
558 | 559 | ||
559 | #define up16(v) (((v)+15) & -16) | 560 | #define up16(v) (((v) + 15) & -16) |
560 | #define down16(v) ((v) & -16) | 561 | #define down16(v) ((v) & -16) |
561 | #define div16(v) ((v)>>4) | 562 | #define div16(v) ((v)>>4) |
562 | #define mod16(v) ((v) & 15) | 563 | #define mod16(v) ((v) & 15) |
563 | 564 | ||
564 | #define up32(v) (((v)+31) & -32) | 565 | #define up32(v) (((v) + 31) & -32) |
565 | #define down32(v) ((v) & -32) | 566 | #define down32(v) ((v) & -32) |
566 | #define div32(v) ((v)>>5) | 567 | #define div32(v) ((v)>>5) |
567 | #define mod32(v) ((v) & 31) | 568 | #define mod32(v) ((v) & 31) |
568 | 569 | ||
569 | #define up64(v) (((v)+63) & -64) | 570 | #define up64(v) (((v) + 63) & -64) |
570 | #define down64(v) ((v) & -64) | 571 | #define down64(v) ((v) & -64) |
571 | #define div64(v) ((v)>>6) | 572 | #define div64(v) ((v)>>6) |
572 | #define mod64(v) ((v) & 63) | 573 | #define mod64(v) ((v) & 63) |
573 | 574 | ||
574 | #define upx(x,v) (((v)+(x)-1) & -(x)) | 575 | #define upx(x, v) (((v) + (x) - 1) & -(x)) |
575 | #define downx(x,v) ((v) & -(x)) | 576 | #define downx(x, v) ((v) & -(x)) |
576 | #define modx(x,v) ((v) & ((x)-1)) | 577 | #define modx(x, v) ((v) & ((x) - 1)) |
577 | 578 | ||
578 | /* if x1 is not a constant, this macro won't make real sense :-) */ | 579 | /* if x1 is not a constant, this macro won't make real sense :-) */ |
579 | #ifdef __mc68000__ | 580 | #ifdef __mc68000__ |
580 | #define DIVUL(x1, x2) ({int res; asm("divul %1,%2,%3": "=d" (res): \ | 581 | #define DIVUL(x1, x2) ({int res; asm("divul %1,%2,%3": "=d" (res): \ |
581 | "d" (x2), "d" ((long)((x1)/0x100000000ULL)), "0" ((long)(x1))); res;}) | 582 | "d" (x2), "d" ((long)((x1) / 0x100000000ULL)), "0" ((long)(x1))); res;}) |
582 | #else | 583 | #else |
583 | /* We know a bit about the numbers, so we can do it this way */ | 584 | /* We know a bit about the numbers, so we can do it this way */ |
584 | #define DIVUL(x1, x2) ((((long)((unsigned long long)x1 >> 8) / x2) << 8) + \ | 585 | #define DIVUL(x1, x2) ((((long)((unsigned long long)x1 >> 8) / x2) << 8) + \ |
@@ -607,7 +608,7 @@ static u_short maxfmode, chipset; | |||
607 | #define VIDEOMEMSIZE_ECS_1M (393216) /* ECS (1MB) : max 1024*768*16 */ | 608 | #define VIDEOMEMSIZE_ECS_1M (393216) /* ECS (1MB) : max 1024*768*16 */ |
608 | #define VIDEOMEMSIZE_OCS (262144) /* OCS : max ca. 800*600*16 */ | 609 | #define VIDEOMEMSIZE_OCS (262144) /* OCS : max ca. 800*600*16 */ |
609 | 610 | ||
610 | #define SPRITEMEMSIZE (64*64/4) /* max 64*64*4 */ | 611 | #define SPRITEMEMSIZE (64 * 64 / 4) /* max 64*64*4 */ |
611 | #define DUMMYSPRITEMEMSIZE (8) | 612 | #define DUMMYSPRITEMEMSIZE (8) |
612 | static u_long spritememory; | 613 | static u_long spritememory; |
613 | 614 | ||
@@ -634,9 +635,9 @@ static u_long min_fstrt = 192; | |||
634 | * Copper Instructions | 635 | * Copper Instructions |
635 | */ | 636 | */ |
636 | 637 | ||
637 | #define CMOVE(val, reg) (CUSTOM_OFS(reg)<<16 | (val)) | 638 | #define CMOVE(val, reg) (CUSTOM_OFS(reg) << 16 | (val)) |
638 | #define CMOVE2(val, reg) ((CUSTOM_OFS(reg)+2)<<16 | (val)) | 639 | #define CMOVE2(val, reg) ((CUSTOM_OFS(reg) + 2) << 16 | (val)) |
639 | #define CWAIT(x, y) (((y) & 0x1fe)<<23 | ((x) & 0x7f0)<<13 | 0x0001fffe) | 640 | #define CWAIT(x, y) (((y) & 0x1fe) << 23 | ((x) & 0x7f0) << 13 | 0x0001fffe) |
640 | #define CEND (0xfffffffe) | 641 | #define CEND (0xfffffffe) |
641 | 642 | ||
642 | 643 | ||
@@ -709,7 +710,7 @@ static u_short *lofsprite, *shfsprite, *dummysprite; | |||
709 | * Current Video Mode | 710 | * Current Video Mode |
710 | */ | 711 | */ |
711 | 712 | ||
712 | static struct amifb_par { | 713 | struct amifb_par { |
713 | 714 | ||
714 | /* General Values */ | 715 | /* General Values */ |
715 | 716 | ||
@@ -772,15 +773,6 @@ static struct amifb_par { | |||
772 | /* Additional AGA Hardware Registers */ | 773 | /* Additional AGA Hardware Registers */ |
773 | 774 | ||
774 | u_short fmode; /* vmode */ | 775 | u_short fmode; /* vmode */ |
775 | } currentpar; | ||
776 | |||
777 | |||
778 | static struct fb_info fb_info = { | ||
779 | .fix = { | ||
780 | .id = "Amiga ", | ||
781 | .visual = FB_VISUAL_PSEUDOCOLOR, | ||
782 | .accel = FB_ACCEL_AMIGABLITT | ||
783 | } | ||
784 | }; | 776 | }; |
785 | 777 | ||
786 | 778 | ||
@@ -820,116 +812,123 @@ static u_short is_lace = 0; /* Screen is laced */ | |||
820 | 812 | ||
821 | static struct fb_videomode ami_modedb[] __initdata = { | 813 | static struct fb_videomode ami_modedb[] __initdata = { |
822 | 814 | ||
823 | /* | 815 | /* |
824 | * AmigaOS Video Modes | 816 | * AmigaOS Video Modes |
825 | * | 817 | * |
826 | * If you change these, make sure to update DEFMODE_* as well! | 818 | * If you change these, make sure to update DEFMODE_* as well! |
827 | */ | 819 | */ |
828 | 820 | ||
829 | { | 821 | { |
830 | /* 640x200, 15 kHz, 60 Hz (NTSC) */ | 822 | /* 640x200, 15 kHz, 60 Hz (NTSC) */ |
831 | "ntsc", 60, 640, 200, TAG_HIRES, 106, 86, 44, 16, 76, 2, | 823 | "ntsc", 60, 640, 200, TAG_HIRES, 106, 86, 44, 16, 76, 2, |
832 | FB_SYNC_BROADCAST, FB_VMODE_NONINTERLACED | FB_VMODE_YWRAP | 824 | FB_SYNC_BROADCAST, FB_VMODE_NONINTERLACED | FB_VMODE_YWRAP |
833 | }, { | 825 | }, { |
834 | /* 640x400, 15 kHz, 60 Hz interlaced (NTSC) */ | 826 | /* 640x400, 15 kHz, 60 Hz interlaced (NTSC) */ |
835 | "ntsc-lace", 60, 640, 400, TAG_HIRES, 106, 86, 88, 33, 76, 4, | 827 | "ntsc-lace", 60, 640, 400, TAG_HIRES, 106, 86, 88, 33, 76, 4, |
836 | FB_SYNC_BROADCAST, FB_VMODE_INTERLACED | FB_VMODE_YWRAP | 828 | FB_SYNC_BROADCAST, FB_VMODE_INTERLACED | FB_VMODE_YWRAP |
837 | }, { | 829 | }, { |
838 | /* 640x256, 15 kHz, 50 Hz (PAL) */ | 830 | /* 640x256, 15 kHz, 50 Hz (PAL) */ |
839 | "pal", 50, 640, 256, TAG_HIRES, 106, 86, 40, 14, 76, 2, | 831 | "pal", 50, 640, 256, TAG_HIRES, 106, 86, 40, 14, 76, 2, |
840 | FB_SYNC_BROADCAST, FB_VMODE_NONINTERLACED | FB_VMODE_YWRAP | 832 | FB_SYNC_BROADCAST, FB_VMODE_NONINTERLACED | FB_VMODE_YWRAP |
841 | }, { | 833 | }, { |
842 | /* 640x512, 15 kHz, 50 Hz interlaced (PAL) */ | 834 | /* 640x512, 15 kHz, 50 Hz interlaced (PAL) */ |
843 | "pal-lace", 50, 640, 512, TAG_HIRES, 106, 86, 80, 29, 76, 4, | 835 | "pal-lace", 50, 640, 512, TAG_HIRES, 106, 86, 80, 29, 76, 4, |
844 | FB_SYNC_BROADCAST, FB_VMODE_INTERLACED | FB_VMODE_YWRAP | 836 | FB_SYNC_BROADCAST, FB_VMODE_INTERLACED | FB_VMODE_YWRAP |
845 | }, { | 837 | }, { |
846 | /* 640x480, 29 kHz, 57 Hz */ | 838 | /* 640x480, 29 kHz, 57 Hz */ |
847 | "multiscan", 57, 640, 480, TAG_SHRES, 96, 112, 29, 8, 72, 8, | 839 | "multiscan", 57, 640, 480, TAG_SHRES, 96, 112, 29, 8, 72, 8, |
848 | 0, FB_VMODE_NONINTERLACED | FB_VMODE_YWRAP | 840 | 0, FB_VMODE_NONINTERLACED | FB_VMODE_YWRAP |
849 | }, { | 841 | }, { |
850 | /* 640x960, 29 kHz, 57 Hz interlaced */ | 842 | /* 640x960, 29 kHz, 57 Hz interlaced */ |
851 | "multiscan-lace", 57, 640, 960, TAG_SHRES, 96, 112, 58, 16, 72, 16, | 843 | "multiscan-lace", 57, 640, 960, TAG_SHRES, 96, 112, 58, 16, 72, |
852 | 0, FB_VMODE_INTERLACED | FB_VMODE_YWRAP | 844 | 16, |
853 | }, { | 845 | 0, FB_VMODE_INTERLACED | FB_VMODE_YWRAP |
854 | /* 640x200, 15 kHz, 72 Hz */ | 846 | }, { |
855 | "euro36", 72, 640, 200, TAG_HIRES, 92, 124, 6, 6, 52, 5, | 847 | /* 640x200, 15 kHz, 72 Hz */ |
856 | 0, FB_VMODE_NONINTERLACED | FB_VMODE_YWRAP | 848 | "euro36", 72, 640, 200, TAG_HIRES, 92, 124, 6, 6, 52, 5, |
857 | }, { | 849 | 0, FB_VMODE_NONINTERLACED | FB_VMODE_YWRAP |
858 | /* 640x400, 15 kHz, 72 Hz interlaced */ | 850 | }, { |
859 | "euro36-lace", 72, 640, 400, TAG_HIRES, 92, 124, 12, 12, 52, 10, | 851 | /* 640x400, 15 kHz, 72 Hz interlaced */ |
860 | 0, FB_VMODE_INTERLACED | FB_VMODE_YWRAP | 852 | "euro36-lace", 72, 640, 400, TAG_HIRES, 92, 124, 12, 12, 52, |
861 | }, { | 853 | 10, |
862 | /* 640x400, 29 kHz, 68 Hz */ | 854 | 0, FB_VMODE_INTERLACED | FB_VMODE_YWRAP |
863 | "euro72", 68, 640, 400, TAG_SHRES, 164, 92, 9, 9, 80, 8, | 855 | }, { |
864 | 0, FB_VMODE_NONINTERLACED | FB_VMODE_YWRAP | 856 | /* 640x400, 29 kHz, 68 Hz */ |
865 | }, { | 857 | "euro72", 68, 640, 400, TAG_SHRES, 164, 92, 9, 9, 80, 8, |
866 | /* 640x800, 29 kHz, 68 Hz interlaced */ | 858 | 0, FB_VMODE_NONINTERLACED | FB_VMODE_YWRAP |
867 | "euro72-lace", 68, 640, 800, TAG_SHRES, 164, 92, 18, 18, 80, 16, | 859 | }, { |
868 | 0, FB_VMODE_INTERLACED | FB_VMODE_YWRAP | 860 | /* 640x800, 29 kHz, 68 Hz interlaced */ |
869 | }, { | 861 | "euro72-lace", 68, 640, 800, TAG_SHRES, 164, 92, 18, 18, 80, |
870 | /* 800x300, 23 kHz, 70 Hz */ | 862 | 16, |
871 | "super72", 70, 800, 300, TAG_SHRES, 212, 140, 10, 11, 80, 7, | 863 | 0, FB_VMODE_INTERLACED | FB_VMODE_YWRAP |
872 | 0, FB_VMODE_NONINTERLACED | FB_VMODE_YWRAP | 864 | }, { |
873 | }, { | 865 | /* 800x300, 23 kHz, 70 Hz */ |
874 | /* 800x600, 23 kHz, 70 Hz interlaced */ | 866 | "super72", 70, 800, 300, TAG_SHRES, 212, 140, 10, 11, 80, 7, |
875 | "super72-lace", 70, 800, 600, TAG_SHRES, 212, 140, 20, 22, 80, 14, | 867 | 0, FB_VMODE_NONINTERLACED | FB_VMODE_YWRAP |
876 | 0, FB_VMODE_INTERLACED | FB_VMODE_YWRAP | 868 | }, { |
877 | }, { | 869 | /* 800x600, 23 kHz, 70 Hz interlaced */ |
878 | /* 640x200, 27 kHz, 57 Hz doublescan */ | 870 | "super72-lace", 70, 800, 600, TAG_SHRES, 212, 140, 20, 22, 80, |
879 | "dblntsc", 57, 640, 200, TAG_SHRES, 196, 124, 18, 17, 80, 4, | 871 | 14, |
880 | 0, FB_VMODE_DOUBLE | FB_VMODE_YWRAP | 872 | 0, FB_VMODE_INTERLACED | FB_VMODE_YWRAP |
881 | }, { | 873 | }, { |
882 | /* 640x400, 27 kHz, 57 Hz */ | 874 | /* 640x200, 27 kHz, 57 Hz doublescan */ |
883 | "dblntsc-ff", 57, 640, 400, TAG_SHRES, 196, 124, 36, 35, 80, 7, | 875 | "dblntsc", 57, 640, 200, TAG_SHRES, 196, 124, 18, 17, 80, 4, |
884 | 0, FB_VMODE_NONINTERLACED | FB_VMODE_YWRAP | 876 | 0, FB_VMODE_DOUBLE | FB_VMODE_YWRAP |
885 | }, { | 877 | }, { |
886 | /* 640x800, 27 kHz, 57 Hz interlaced */ | 878 | /* 640x400, 27 kHz, 57 Hz */ |
887 | "dblntsc-lace", 57, 640, 800, TAG_SHRES, 196, 124, 72, 70, 80, 14, | 879 | "dblntsc-ff", 57, 640, 400, TAG_SHRES, 196, 124, 36, 35, 80, 7, |
888 | 0, FB_VMODE_INTERLACED | FB_VMODE_YWRAP | 880 | 0, FB_VMODE_NONINTERLACED | FB_VMODE_YWRAP |
889 | }, { | 881 | }, { |
890 | /* 640x256, 27 kHz, 47 Hz doublescan */ | 882 | /* 640x800, 27 kHz, 57 Hz interlaced */ |
891 | "dblpal", 47, 640, 256, TAG_SHRES, 196, 124, 14, 13, 80, 4, | 883 | "dblntsc-lace", 57, 640, 800, TAG_SHRES, 196, 124, 72, 70, 80, |
892 | 0, FB_VMODE_DOUBLE | FB_VMODE_YWRAP | 884 | 14, |
893 | }, { | 885 | 0, FB_VMODE_INTERLACED | FB_VMODE_YWRAP |
894 | /* 640x512, 27 kHz, 47 Hz */ | 886 | }, { |
895 | "dblpal-ff", 47, 640, 512, TAG_SHRES, 196, 124, 28, 27, 80, 7, | 887 | /* 640x256, 27 kHz, 47 Hz doublescan */ |
896 | 0, FB_VMODE_NONINTERLACED | FB_VMODE_YWRAP | 888 | "dblpal", 47, 640, 256, TAG_SHRES, 196, 124, 14, 13, 80, 4, |
897 | }, { | 889 | 0, FB_VMODE_DOUBLE | FB_VMODE_YWRAP |
898 | /* 640x1024, 27 kHz, 47 Hz interlaced */ | 890 | }, { |
899 | "dblpal-lace", 47, 640, 1024, TAG_SHRES, 196, 124, 56, 54, 80, 14, | 891 | /* 640x512, 27 kHz, 47 Hz */ |
900 | 0, FB_VMODE_INTERLACED | FB_VMODE_YWRAP | 892 | "dblpal-ff", 47, 640, 512, TAG_SHRES, 196, 124, 28, 27, 80, 7, |
901 | }, | 893 | 0, FB_VMODE_NONINTERLACED | FB_VMODE_YWRAP |
902 | 894 | }, { | |
903 | /* | 895 | /* 640x1024, 27 kHz, 47 Hz interlaced */ |
904 | * VGA Video Modes | 896 | "dblpal-lace", 47, 640, 1024, TAG_SHRES, 196, 124, 56, 54, 80, |
905 | */ | 897 | 14, |
906 | 898 | 0, FB_VMODE_INTERLACED | FB_VMODE_YWRAP | |
907 | { | 899 | }, |
908 | /* 640x480, 31 kHz, 60 Hz (VGA) */ | 900 | |
909 | "vga", 60, 640, 480, TAG_SHRES, 64, 96, 30, 9, 112, 2, | 901 | /* |
910 | 0, FB_VMODE_NONINTERLACED | FB_VMODE_YWRAP | 902 | * VGA Video Modes |
911 | }, { | 903 | */ |
912 | /* 640x400, 31 kHz, 70 Hz (VGA) */ | 904 | |
913 | "vga70", 70, 640, 400, TAG_SHRES, 64, 96, 35, 12, 112, 2, | 905 | { |
914 | FB_SYNC_VERT_HIGH_ACT | FB_SYNC_COMP_HIGH_ACT, FB_VMODE_NONINTERLACED | FB_VMODE_YWRAP | 906 | /* 640x480, 31 kHz, 60 Hz (VGA) */ |
915 | }, | 907 | "vga", 60, 640, 480, TAG_SHRES, 64, 96, 30, 9, 112, 2, |
908 | 0, FB_VMODE_NONINTERLACED | FB_VMODE_YWRAP | ||
909 | }, { | ||
910 | /* 640x400, 31 kHz, 70 Hz (VGA) */ | ||
911 | "vga70", 70, 640, 400, TAG_SHRES, 64, 96, 35, 12, 112, 2, | ||
912 | FB_SYNC_VERT_HIGH_ACT | FB_SYNC_COMP_HIGH_ACT, | ||
913 | FB_VMODE_NONINTERLACED | FB_VMODE_YWRAP | ||
914 | }, | ||
916 | 915 | ||
917 | #if 0 | 916 | #if 0 |
918 | 917 | ||
919 | /* | 918 | /* |
920 | * A2024 video modes | 919 | * A2024 video modes |
921 | * These modes don't work yet because there's no A2024 driver. | 920 | * These modes don't work yet because there's no A2024 driver. |
922 | */ | 921 | */ |
923 | 922 | ||
924 | { | 923 | { |
925 | /* 1024x800, 10 Hz */ | 924 | /* 1024x800, 10 Hz */ |
926 | "a2024-10", 10, 1024, 800, TAG_HIRES, 0, 0, 0, 0, 0, 0, | 925 | "a2024-10", 10, 1024, 800, TAG_HIRES, 0, 0, 0, 0, 0, 0, |
927 | 0, FB_VMODE_NONINTERLACED | FB_VMODE_YWRAP | 926 | 0, FB_VMODE_NONINTERLACED | FB_VMODE_YWRAP |
928 | }, { | 927 | }, { |
929 | /* 1024x800, 15 Hz */ | 928 | /* 1024x800, 15 Hz */ |
930 | "a2024-15", 15, 1024, 800, TAG_HIRES, 0, 0, 0, 0, 0, 0, | 929 | "a2024-15", 15, 1024, 800, TAG_HIRES, 0, 0, 0, 0, 0, 0, |
931 | 0, FB_VMODE_NONINTERLACED | FB_VMODE_YWRAP | 930 | 0, FB_VMODE_NONINTERLACED | FB_VMODE_YWRAP |
932 | } | 931 | } |
933 | #endif | 932 | #endif |
934 | }; | 933 | }; |
935 | 934 | ||
@@ -953,6 +952,11 @@ static int round_down_bpp = 1; /* for mode probing */ | |||
953 | static int amifb_ilbm = 0; /* interleaved or normal bitplanes */ | 952 | static int amifb_ilbm = 0; /* interleaved or normal bitplanes */ |
954 | static int amifb_inverse = 0; | 953 | static int amifb_inverse = 0; |
955 | 954 | ||
955 | static u32 amifb_hfmin __initdata; /* monitor hfreq lower limit (Hz) */ | ||
956 | static u32 amifb_hfmax __initdata; /* monitor hfreq upper limit (Hz) */ | ||
957 | static u16 amifb_vfmin __initdata; /* monitor vfreq lower limit (Hz) */ | ||
958 | static u16 amifb_vfmax __initdata; /* monitor vfreq upper limit (Hz) */ | ||
959 | |||
956 | 960 | ||
957 | /* | 961 | /* |
958 | * Macros for the conversion from real world values to hardware register | 962 | * Macros for the conversion from real world values to hardware register |
@@ -992,19 +996,20 @@ static int amifb_inverse = 0; | |||
992 | /* bplcon1 (smooth scrolling) */ | 996 | /* bplcon1 (smooth scrolling) */ |
993 | 997 | ||
994 | #define hscroll2hw(hscroll) \ | 998 | #define hscroll2hw(hscroll) \ |
995 | (((hscroll)<<12 & 0x3000) | ((hscroll)<<8 & 0xc300) | \ | 999 | (((hscroll) << 12 & 0x3000) | ((hscroll) << 8 & 0xc300) | \ |
996 | ((hscroll)<<4 & 0x0c00) | ((hscroll)<<2 & 0x00f0) | ((hscroll)>>2 & 0x000f)) | 1000 | ((hscroll) << 4 & 0x0c00) | ((hscroll) << 2 & 0x00f0) | \ |
1001 | ((hscroll)>>2 & 0x000f)) | ||
997 | 1002 | ||
998 | /* diwstrt/diwstop/diwhigh (visible display window) */ | 1003 | /* diwstrt/diwstop/diwhigh (visible display window) */ |
999 | 1004 | ||
1000 | #define diwstrt2hw(diwstrt_h, diwstrt_v) \ | 1005 | #define diwstrt2hw(diwstrt_h, diwstrt_v) \ |
1001 | (((diwstrt_v)<<7 & 0xff00) | ((diwstrt_h)>>2 & 0x00ff)) | 1006 | (((diwstrt_v) << 7 & 0xff00) | ((diwstrt_h)>>2 & 0x00ff)) |
1002 | #define diwstop2hw(diwstop_h, diwstop_v) \ | 1007 | #define diwstop2hw(diwstop_h, diwstop_v) \ |
1003 | (((diwstop_v)<<7 & 0xff00) | ((diwstop_h)>>2 & 0x00ff)) | 1008 | (((diwstop_v) << 7 & 0xff00) | ((diwstop_h)>>2 & 0x00ff)) |
1004 | #define diwhigh2hw(diwstrt_h, diwstrt_v, diwstop_h, diwstop_v) \ | 1009 | #define diwhigh2hw(diwstrt_h, diwstrt_v, diwstop_h, diwstop_v) \ |
1005 | (((diwstop_h)<<3 & 0x2000) | ((diwstop_h)<<11 & 0x1800) | \ | 1010 | (((diwstop_h) << 3 & 0x2000) | ((diwstop_h) << 11 & 0x1800) | \ |
1006 | ((diwstop_v)>>1 & 0x0700) | ((diwstrt_h)>>5 & 0x0020) | \ | 1011 | ((diwstop_v)>>1 & 0x0700) | ((diwstrt_h)>>5 & 0x0020) | \ |
1007 | ((diwstrt_h)<<3 & 0x0018) | ((diwstrt_v)>>9 & 0x0007)) | 1012 | ((diwstrt_h) << 3 & 0x0018) | ((diwstrt_v)>>9 & 0x0007)) |
1008 | 1013 | ||
1009 | /* ddfstrt/ddfstop (display DMA) */ | 1014 | /* ddfstrt/ddfstop (display DMA) */ |
1010 | 1015 | ||
@@ -1015,38 +1020,39 @@ static int amifb_inverse = 0; | |||
1015 | 1020 | ||
1016 | #define hsstrt2hw(hsstrt) (div8(hsstrt)) | 1021 | #define hsstrt2hw(hsstrt) (div8(hsstrt)) |
1017 | #define hsstop2hw(hsstop) (div8(hsstop)) | 1022 | #define hsstop2hw(hsstop) (div8(hsstop)) |
1018 | #define htotal2hw(htotal) (div8(htotal)-1) | 1023 | #define htotal2hw(htotal) (div8(htotal) - 1) |
1019 | #define vsstrt2hw(vsstrt) (div2(vsstrt)) | 1024 | #define vsstrt2hw(vsstrt) (div2(vsstrt)) |
1020 | #define vsstop2hw(vsstop) (div2(vsstop)) | 1025 | #define vsstop2hw(vsstop) (div2(vsstop)) |
1021 | #define vtotal2hw(vtotal) (div2(vtotal)-1) | 1026 | #define vtotal2hw(vtotal) (div2(vtotal) - 1) |
1022 | #define hcenter2hw(htotal) (div8(htotal)) | 1027 | #define hcenter2hw(htotal) (div8(htotal)) |
1023 | 1028 | ||
1024 | /* hbstrt/hbstop/vbstrt/vbstop (blanking timings) */ | 1029 | /* hbstrt/hbstop/vbstrt/vbstop (blanking timings) */ |
1025 | 1030 | ||
1026 | #define hbstrt2hw(hbstrt) (((hbstrt)<<8 & 0x0700) | ((hbstrt)>>3 & 0x00ff)) | 1031 | #define hbstrt2hw(hbstrt) (((hbstrt) << 8 & 0x0700) | ((hbstrt)>>3 & 0x00ff)) |
1027 | #define hbstop2hw(hbstop) (((hbstop)<<8 & 0x0700) | ((hbstop)>>3 & 0x00ff)) | 1032 | #define hbstop2hw(hbstop) (((hbstop) << 8 & 0x0700) | ((hbstop)>>3 & 0x00ff)) |
1028 | #define vbstrt2hw(vbstrt) (div2(vbstrt)) | 1033 | #define vbstrt2hw(vbstrt) (div2(vbstrt)) |
1029 | #define vbstop2hw(vbstop) (div2(vbstop)) | 1034 | #define vbstop2hw(vbstop) (div2(vbstop)) |
1030 | 1035 | ||
1031 | /* colour */ | 1036 | /* colour */ |
1032 | 1037 | ||
1033 | #define rgb2hw8_high(red, green, blue) \ | 1038 | #define rgb2hw8_high(red, green, blue) \ |
1034 | (((red & 0xf0)<<4) | (green & 0xf0) | ((blue & 0xf0)>>4)) | 1039 | (((red & 0xf0) << 4) | (green & 0xf0) | ((blue & 0xf0)>>4)) |
1035 | #define rgb2hw8_low(red, green, blue) \ | 1040 | #define rgb2hw8_low(red, green, blue) \ |
1036 | (((red & 0x0f)<<8) | ((green & 0x0f)<<4) | (blue & 0x0f)) | 1041 | (((red & 0x0f) << 8) | ((green & 0x0f) << 4) | (blue & 0x0f)) |
1037 | #define rgb2hw4(red, green, blue) \ | 1042 | #define rgb2hw4(red, green, blue) \ |
1038 | (((red & 0xf0)<<4) | (green & 0xf0) | ((blue & 0xf0)>>4)) | 1043 | (((red & 0xf0) << 4) | (green & 0xf0) | ((blue & 0xf0)>>4)) |
1039 | #define rgb2hw2(red, green, blue) \ | 1044 | #define rgb2hw2(red, green, blue) \ |
1040 | (((red & 0xc0)<<4) | (green & 0xc0) | ((blue & 0xc0)>>4)) | 1045 | (((red & 0xc0) << 4) | (green & 0xc0) | ((blue & 0xc0)>>4)) |
1041 | 1046 | ||
1042 | /* sprpos/sprctl (sprite positioning) */ | 1047 | /* sprpos/sprctl (sprite positioning) */ |
1043 | 1048 | ||
1044 | #define spr2hw_pos(start_v, start_h) \ | 1049 | #define spr2hw_pos(start_v, start_h) \ |
1045 | (((start_v)<<7&0xff00) | ((start_h)>>3&0x00ff)) | 1050 | (((start_v) << 7 & 0xff00) | ((start_h)>>3 & 0x00ff)) |
1046 | #define spr2hw_ctl(start_v, start_h, stop_v) \ | 1051 | #define spr2hw_ctl(start_v, start_h, stop_v) \ |
1047 | (((stop_v)<<7&0xff00) | ((start_v)>>4&0x0040) | ((stop_v)>>5&0x0020) | \ | 1052 | (((stop_v) << 7 & 0xff00) | ((start_v)>>4 & 0x0040) | \ |
1048 | ((start_h)<<3&0x0018) | ((start_v)>>7&0x0004) | ((stop_v)>>8&0x0002) | \ | 1053 | ((stop_v)>>5 & 0x0020) | ((start_h) << 3 & 0x0018) | \ |
1049 | ((start_h)>>2&0x0001)) | 1054 | ((start_v)>>7 & 0x0004) | ((stop_v)>>8 & 0x0002) | \ |
1055 | ((start_h)>>2 & 0x0001)) | ||
1050 | 1056 | ||
1051 | /* get current vertical position of beam */ | 1057 | /* get current vertical position of beam */ |
1052 | #define get_vbpos() ((u_short)((*(u_long volatile *)&custom.vposr >> 7) & 0xffe)) | 1058 | #define get_vbpos() ((u_short)((*(u_long volatile *)&custom.vposr >> 7) & 0xffe)) |
@@ -1055,7 +1061,7 @@ static int amifb_inverse = 0; | |||
1055 | * Copper Initialisation List | 1061 | * Copper Initialisation List |
1056 | */ | 1062 | */ |
1057 | 1063 | ||
1058 | #define COPINITSIZE (sizeof(copins)*40) | 1064 | #define COPINITSIZE (sizeof(copins) * 40) |
1059 | 1065 | ||
1060 | enum { | 1066 | enum { |
1061 | cip_bplcon0 | 1067 | cip_bplcon0 |
@@ -1066,7 +1072,7 @@ enum { | |||
1066 | * Don't change the order, build_copper()/rebuild_copper() rely on this | 1072 | * Don't change the order, build_copper()/rebuild_copper() rely on this |
1067 | */ | 1073 | */ |
1068 | 1074 | ||
1069 | #define COPLISTSIZE (sizeof(copins)*64) | 1075 | #define COPLISTSIZE (sizeof(copins) * 64) |
1070 | 1076 | ||
1071 | enum { | 1077 | enum { |
1072 | cop_wait, cop_bplcon0, | 1078 | cop_wait, cop_bplcon0, |
@@ -1108,82 +1114,1199 @@ static u_short sprfetchmode[3] = { | |||
1108 | }; | 1114 | }; |
1109 | 1115 | ||
1110 | 1116 | ||
1117 | /* --------------------------- Hardware routines --------------------------- */ | ||
1118 | |||
1111 | /* | 1119 | /* |
1112 | * Interface used by the world | 1120 | * Get the video params out of `var'. If a value doesn't fit, round |
1121 | * it up, if it's too big, return -EINVAL. | ||
1113 | */ | 1122 | */ |
1114 | 1123 | ||
1115 | int amifb_setup(char*); | 1124 | static int ami_decode_var(struct fb_var_screeninfo *var, struct amifb_par *par, |
1125 | const struct fb_info *info) | ||
1126 | { | ||
1127 | u_short clk_shift, line_shift; | ||
1128 | u_long maxfetchstop, fstrt, fsize, fconst, xres_n, yres_n; | ||
1129 | u_int htotal, vtotal; | ||
1116 | 1130 | ||
1117 | static int amifb_check_var(struct fb_var_screeninfo *var, | 1131 | /* |
1118 | struct fb_info *info); | 1132 | * Find a matching Pixel Clock |
1119 | static int amifb_set_par(struct fb_info *info); | 1133 | */ |
1120 | static int amifb_setcolreg(unsigned regno, unsigned red, unsigned green, | ||
1121 | unsigned blue, unsigned transp, | ||
1122 | struct fb_info *info); | ||
1123 | static int amifb_blank(int blank, struct fb_info *info); | ||
1124 | static int amifb_pan_display(struct fb_var_screeninfo *var, | ||
1125 | struct fb_info *info); | ||
1126 | static void amifb_fillrect(struct fb_info *info, | ||
1127 | const struct fb_fillrect *rect); | ||
1128 | static void amifb_copyarea(struct fb_info *info, | ||
1129 | const struct fb_copyarea *region); | ||
1130 | static void amifb_imageblit(struct fb_info *info, | ||
1131 | const struct fb_image *image); | ||
1132 | static int amifb_ioctl(struct fb_info *info, unsigned int cmd, unsigned long arg); | ||
1133 | 1134 | ||
1135 | for (clk_shift = TAG_SHRES; clk_shift <= TAG_LORES; clk_shift++) | ||
1136 | if (var->pixclock <= pixclock[clk_shift]) | ||
1137 | break; | ||
1138 | if (clk_shift > TAG_LORES) { | ||
1139 | DPRINTK("pixclock too high\n"); | ||
1140 | return -EINVAL; | ||
1141 | } | ||
1142 | par->clk_shift = clk_shift; | ||
1134 | 1143 | ||
1135 | /* | 1144 | /* |
1136 | * Interface to the low level console driver | 1145 | * Check the Geometry Values |
1137 | */ | 1146 | */ |
1138 | 1147 | ||
1139 | static void amifb_deinit(struct platform_device *pdev); | 1148 | if ((par->xres = var->xres) < 64) |
1149 | par->xres = 64; | ||
1150 | if ((par->yres = var->yres) < 64) | ||
1151 | par->yres = 64; | ||
1152 | if ((par->vxres = var->xres_virtual) < par->xres) | ||
1153 | par->vxres = par->xres; | ||
1154 | if ((par->vyres = var->yres_virtual) < par->yres) | ||
1155 | par->vyres = par->yres; | ||
1156 | |||
1157 | par->bpp = var->bits_per_pixel; | ||
1158 | if (!var->nonstd) { | ||
1159 | if (par->bpp < 1) | ||
1160 | par->bpp = 1; | ||
1161 | if (par->bpp > maxdepth[clk_shift]) { | ||
1162 | if (round_down_bpp && maxdepth[clk_shift]) | ||
1163 | par->bpp = maxdepth[clk_shift]; | ||
1164 | else { | ||
1165 | DPRINTK("invalid bpp\n"); | ||
1166 | return -EINVAL; | ||
1167 | } | ||
1168 | } | ||
1169 | } else if (var->nonstd == FB_NONSTD_HAM) { | ||
1170 | if (par->bpp < 6) | ||
1171 | par->bpp = 6; | ||
1172 | if (par->bpp != 6) { | ||
1173 | if (par->bpp < 8) | ||
1174 | par->bpp = 8; | ||
1175 | if (par->bpp != 8 || !IS_AGA) { | ||
1176 | DPRINTK("invalid bpp for ham mode\n"); | ||
1177 | return -EINVAL; | ||
1178 | } | ||
1179 | } | ||
1180 | } else { | ||
1181 | DPRINTK("unknown nonstd mode\n"); | ||
1182 | return -EINVAL; | ||
1183 | } | ||
1140 | 1184 | ||
1141 | /* | 1185 | /* |
1142 | * Internal routines | 1186 | * FB_VMODE_SMOOTH_XPAN will be cleared, if one of the folloing |
1187 | * checks failed and smooth scrolling is not possible | ||
1143 | */ | 1188 | */ |
1144 | 1189 | ||
1145 | static int flash_cursor(void); | 1190 | par->vmode = var->vmode | FB_VMODE_SMOOTH_XPAN; |
1146 | static irqreturn_t amifb_interrupt(int irq, void *dev_id); | 1191 | switch (par->vmode & FB_VMODE_MASK) { |
1147 | static u_long chipalloc(u_long size); | 1192 | case FB_VMODE_INTERLACED: |
1148 | static void chipfree(void); | 1193 | line_shift = 0; |
1194 | break; | ||
1195 | case FB_VMODE_NONINTERLACED: | ||
1196 | line_shift = 1; | ||
1197 | break; | ||
1198 | case FB_VMODE_DOUBLE: | ||
1199 | if (!IS_AGA) { | ||
1200 | DPRINTK("double mode only possible with aga\n"); | ||
1201 | return -EINVAL; | ||
1202 | } | ||
1203 | line_shift = 2; | ||
1204 | break; | ||
1205 | default: | ||
1206 | DPRINTK("unknown video mode\n"); | ||
1207 | return -EINVAL; | ||
1208 | break; | ||
1209 | } | ||
1210 | par->line_shift = line_shift; | ||
1149 | 1211 | ||
1150 | /* | 1212 | /* |
1151 | * Hardware routines | 1213 | * Vertical and Horizontal Timings |
1152 | */ | 1214 | */ |
1153 | 1215 | ||
1154 | static int ami_decode_var(struct fb_var_screeninfo *var, | 1216 | xres_n = par->xres << clk_shift; |
1155 | struct amifb_par *par); | 1217 | yres_n = par->yres << line_shift; |
1156 | static int ami_encode_var(struct fb_var_screeninfo *var, | 1218 | par->htotal = down8((var->left_margin + par->xres + var->right_margin + |
1157 | struct amifb_par *par); | 1219 | var->hsync_len) << clk_shift); |
1158 | static void ami_pan_var(struct fb_var_screeninfo *var); | 1220 | par->vtotal = |
1159 | static int ami_update_par(void); | 1221 | down2(((var->upper_margin + par->yres + var->lower_margin + |
1160 | static void ami_update_display(void); | 1222 | var->vsync_len) << line_shift) + 1); |
1161 | static void ami_init_display(void); | ||
1162 | static void ami_do_blank(void); | ||
1163 | static int ami_get_fix_cursorinfo(struct fb_fix_cursorinfo *fix); | ||
1164 | static int ami_get_var_cursorinfo(struct fb_var_cursorinfo *var, u_char __user *data); | ||
1165 | static int ami_set_var_cursorinfo(struct fb_var_cursorinfo *var, u_char __user *data); | ||
1166 | static int ami_get_cursorstate(struct fb_cursorstate *state); | ||
1167 | static int ami_set_cursorstate(struct fb_cursorstate *state); | ||
1168 | static void ami_set_sprite(void); | ||
1169 | static void ami_init_copper(void); | ||
1170 | static void ami_reinit_copper(void); | ||
1171 | static void ami_build_copper(void); | ||
1172 | static void ami_rebuild_copper(void); | ||
1173 | 1223 | ||
1224 | if (IS_AGA) | ||
1225 | par->bplcon3 = sprpixmode[clk_shift]; | ||
1226 | else | ||
1227 | par->bplcon3 = 0; | ||
1228 | if (var->sync & FB_SYNC_BROADCAST) { | ||
1229 | par->diwstop_h = par->htotal - | ||
1230 | ((var->right_margin - var->hsync_len) << clk_shift); | ||
1231 | if (IS_AGA) | ||
1232 | par->diwstop_h += mod4(var->hsync_len); | ||
1233 | else | ||
1234 | par->diwstop_h = down4(par->diwstop_h); | ||
1235 | |||
1236 | par->diwstrt_h = par->diwstop_h - xres_n; | ||
1237 | par->diwstop_v = par->vtotal - | ||
1238 | ((var->lower_margin - var->vsync_len) << line_shift); | ||
1239 | par->diwstrt_v = par->diwstop_v - yres_n; | ||
1240 | if (par->diwstop_h >= par->htotal + 8) { | ||
1241 | DPRINTK("invalid diwstop_h\n"); | ||
1242 | return -EINVAL; | ||
1243 | } | ||
1244 | if (par->diwstop_v > par->vtotal) { | ||
1245 | DPRINTK("invalid diwstop_v\n"); | ||
1246 | return -EINVAL; | ||
1247 | } | ||
1248 | |||
1249 | if (!IS_OCS) { | ||
1250 | /* Initialize sync with some reasonable values for pwrsave */ | ||
1251 | par->hsstrt = 160; | ||
1252 | par->hsstop = 320; | ||
1253 | par->vsstrt = 30; | ||
1254 | par->vsstop = 34; | ||
1255 | } else { | ||
1256 | par->hsstrt = 0; | ||
1257 | par->hsstop = 0; | ||
1258 | par->vsstrt = 0; | ||
1259 | par->vsstop = 0; | ||
1260 | } | ||
1261 | if (par->vtotal > (PAL_VTOTAL + NTSC_VTOTAL) / 2) { | ||
1262 | /* PAL video mode */ | ||
1263 | if (par->htotal != PAL_HTOTAL) { | ||
1264 | DPRINTK("htotal invalid for pal\n"); | ||
1265 | return -EINVAL; | ||
1266 | } | ||
1267 | if (par->diwstrt_h < PAL_DIWSTRT_H) { | ||
1268 | DPRINTK("diwstrt_h too low for pal\n"); | ||
1269 | return -EINVAL; | ||
1270 | } | ||
1271 | if (par->diwstrt_v < PAL_DIWSTRT_V) { | ||
1272 | DPRINTK("diwstrt_v too low for pal\n"); | ||
1273 | return -EINVAL; | ||
1274 | } | ||
1275 | htotal = PAL_HTOTAL>>clk_shift; | ||
1276 | vtotal = PAL_VTOTAL>>1; | ||
1277 | if (!IS_OCS) { | ||
1278 | par->beamcon0 = BMC0_PAL; | ||
1279 | par->bplcon3 |= BPC3_BRDRBLNK; | ||
1280 | } else if (AMIGAHW_PRESENT(AGNUS_HR_PAL) || | ||
1281 | AMIGAHW_PRESENT(AGNUS_HR_NTSC)) { | ||
1282 | par->beamcon0 = BMC0_PAL; | ||
1283 | par->hsstop = 1; | ||
1284 | } else if (amiga_vblank != 50) { | ||
1285 | DPRINTK("pal not supported by this chipset\n"); | ||
1286 | return -EINVAL; | ||
1287 | } | ||
1288 | } else { | ||
1289 | /* NTSC video mode | ||
1290 | * In the AGA chipset seems to be hardware bug with BPC3_BRDRBLNK | ||
1291 | * and NTSC activated, so than better let diwstop_h <= 1812 | ||
1292 | */ | ||
1293 | if (par->htotal != NTSC_HTOTAL) { | ||
1294 | DPRINTK("htotal invalid for ntsc\n"); | ||
1295 | return -EINVAL; | ||
1296 | } | ||
1297 | if (par->diwstrt_h < NTSC_DIWSTRT_H) { | ||
1298 | DPRINTK("diwstrt_h too low for ntsc\n"); | ||
1299 | return -EINVAL; | ||
1300 | } | ||
1301 | if (par->diwstrt_v < NTSC_DIWSTRT_V) { | ||
1302 | DPRINTK("diwstrt_v too low for ntsc\n"); | ||
1303 | return -EINVAL; | ||
1304 | } | ||
1305 | htotal = NTSC_HTOTAL>>clk_shift; | ||
1306 | vtotal = NTSC_VTOTAL>>1; | ||
1307 | if (!IS_OCS) { | ||
1308 | par->beamcon0 = 0; | ||
1309 | par->bplcon3 |= BPC3_BRDRBLNK; | ||
1310 | } else if (AMIGAHW_PRESENT(AGNUS_HR_PAL) || | ||
1311 | AMIGAHW_PRESENT(AGNUS_HR_NTSC)) { | ||
1312 | par->beamcon0 = 0; | ||
1313 | par->hsstop = 1; | ||
1314 | } else if (amiga_vblank != 60) { | ||
1315 | DPRINTK("ntsc not supported by this chipset\n"); | ||
1316 | return -EINVAL; | ||
1317 | } | ||
1318 | } | ||
1319 | if (IS_OCS) { | ||
1320 | if (par->diwstrt_h >= 1024 || par->diwstop_h < 1024 || | ||
1321 | par->diwstrt_v >= 512 || par->diwstop_v < 256) { | ||
1322 | DPRINTK("invalid position for display on ocs\n"); | ||
1323 | return -EINVAL; | ||
1324 | } | ||
1325 | } | ||
1326 | } else if (!IS_OCS) { | ||
1327 | /* Programmable video mode */ | ||
1328 | par->hsstrt = var->right_margin << clk_shift; | ||
1329 | par->hsstop = (var->right_margin + var->hsync_len) << clk_shift; | ||
1330 | par->diwstop_h = par->htotal - mod8(par->hsstrt) + 8 - (1 << clk_shift); | ||
1331 | if (!IS_AGA) | ||
1332 | par->diwstop_h = down4(par->diwstop_h) - 16; | ||
1333 | par->diwstrt_h = par->diwstop_h - xres_n; | ||
1334 | par->hbstop = par->diwstrt_h + 4; | ||
1335 | par->hbstrt = par->diwstop_h + 4; | ||
1336 | if (par->hbstrt >= par->htotal + 8) | ||
1337 | par->hbstrt -= par->htotal; | ||
1338 | par->hcenter = par->hsstrt + (par->htotal >> 1); | ||
1339 | par->vsstrt = var->lower_margin << line_shift; | ||
1340 | par->vsstop = (var->lower_margin + var->vsync_len) << line_shift; | ||
1341 | par->diwstop_v = par->vtotal; | ||
1342 | if ((par->vmode & FB_VMODE_MASK) == FB_VMODE_INTERLACED) | ||
1343 | par->diwstop_v -= 2; | ||
1344 | par->diwstrt_v = par->diwstop_v - yres_n; | ||
1345 | par->vbstop = par->diwstrt_v - 2; | ||
1346 | par->vbstrt = par->diwstop_v - 2; | ||
1347 | if (par->vtotal > 2048) { | ||
1348 | DPRINTK("vtotal too high\n"); | ||
1349 | return -EINVAL; | ||
1350 | } | ||
1351 | if (par->htotal > 2048) { | ||
1352 | DPRINTK("htotal too high\n"); | ||
1353 | return -EINVAL; | ||
1354 | } | ||
1355 | par->bplcon3 |= BPC3_EXTBLKEN; | ||
1356 | par->beamcon0 = BMC0_HARDDIS | BMC0_VARVBEN | BMC0_LOLDIS | | ||
1357 | BMC0_VARVSYEN | BMC0_VARHSYEN | BMC0_VARBEAMEN | | ||
1358 | BMC0_PAL | BMC0_VARCSYEN; | ||
1359 | if (var->sync & FB_SYNC_HOR_HIGH_ACT) | ||
1360 | par->beamcon0 |= BMC0_HSYTRUE; | ||
1361 | if (var->sync & FB_SYNC_VERT_HIGH_ACT) | ||
1362 | par->beamcon0 |= BMC0_VSYTRUE; | ||
1363 | if (var->sync & FB_SYNC_COMP_HIGH_ACT) | ||
1364 | par->beamcon0 |= BMC0_CSYTRUE; | ||
1365 | htotal = par->htotal>>clk_shift; | ||
1366 | vtotal = par->vtotal>>1; | ||
1367 | } else { | ||
1368 | DPRINTK("only broadcast modes possible for ocs\n"); | ||
1369 | return -EINVAL; | ||
1370 | } | ||
1371 | |||
1372 | /* | ||
1373 | * Checking the DMA timing | ||
1374 | */ | ||
1375 | |||
1376 | fconst = 16 << maxfmode << clk_shift; | ||
1377 | |||
1378 | /* | ||
1379 | * smallest window start value without turn off other dma cycles | ||
1380 | * than sprite1-7, unless you change min_fstrt | ||
1381 | */ | ||
1382 | |||
1383 | |||
1384 | fsize = ((maxfmode + clk_shift <= 1) ? fconst : 64); | ||
1385 | fstrt = downx(fconst, par->diwstrt_h - 4) - fsize; | ||
1386 | if (fstrt < min_fstrt) { | ||
1387 | DPRINTK("fetch start too low\n"); | ||
1388 | return -EINVAL; | ||
1389 | } | ||
1390 | |||
1391 | /* | ||
1392 | * smallest window start value where smooth scrolling is possible | ||
1393 | */ | ||
1394 | |||
1395 | fstrt = downx(fconst, par->diwstrt_h - fconst + (1 << clk_shift) - 4) - | ||
1396 | fsize; | ||
1397 | if (fstrt < min_fstrt) | ||
1398 | par->vmode &= ~FB_VMODE_SMOOTH_XPAN; | ||
1399 | |||
1400 | maxfetchstop = down16(par->htotal - 80); | ||
1401 | |||
1402 | fstrt = downx(fconst, par->diwstrt_h - 4) - 64 - fconst; | ||
1403 | fsize = upx(fconst, xres_n + | ||
1404 | modx(fconst, downx(1 << clk_shift, par->diwstrt_h - 4))); | ||
1405 | if (fstrt + fsize > maxfetchstop) | ||
1406 | par->vmode &= ~FB_VMODE_SMOOTH_XPAN; | ||
1407 | |||
1408 | fsize = upx(fconst, xres_n); | ||
1409 | if (fstrt + fsize > maxfetchstop) { | ||
1410 | DPRINTK("fetch stop too high\n"); | ||
1411 | return -EINVAL; | ||
1412 | } | ||
1413 | |||
1414 | if (maxfmode + clk_shift <= 1) { | ||
1415 | fsize = up64(xres_n + fconst - 1); | ||
1416 | if (min_fstrt + fsize - 64 > maxfetchstop) | ||
1417 | par->vmode &= ~FB_VMODE_SMOOTH_XPAN; | ||
1418 | |||
1419 | fsize = up64(xres_n); | ||
1420 | if (min_fstrt + fsize - 64 > maxfetchstop) { | ||
1421 | DPRINTK("fetch size too high\n"); | ||
1422 | return -EINVAL; | ||
1423 | } | ||
1424 | |||
1425 | fsize -= 64; | ||
1426 | } else | ||
1427 | fsize -= fconst; | ||
1428 | |||
1429 | /* | ||
1430 | * Check if there is enough time to update the bitplane pointers for ywrap | ||
1431 | */ | ||
1432 | |||
1433 | if (par->htotal - fsize - 64 < par->bpp * 64) | ||
1434 | par->vmode &= ~FB_VMODE_YWRAP; | ||
1435 | |||
1436 | /* | ||
1437 | * Bitplane calculations and check the Memory Requirements | ||
1438 | */ | ||
1439 | |||
1440 | if (amifb_ilbm) { | ||
1441 | par->next_plane = div8(upx(16 << maxfmode, par->vxres)); | ||
1442 | par->next_line = par->bpp * par->next_plane; | ||
1443 | if (par->next_line * par->vyres > info->fix.smem_len) { | ||
1444 | DPRINTK("too few video mem\n"); | ||
1445 | return -EINVAL; | ||
1446 | } | ||
1447 | } else { | ||
1448 | par->next_line = div8(upx(16 << maxfmode, par->vxres)); | ||
1449 | par->next_plane = par->vyres * par->next_line; | ||
1450 | if (par->next_plane * par->bpp > info->fix.smem_len) { | ||
1451 | DPRINTK("too few video mem\n"); | ||
1452 | return -EINVAL; | ||
1453 | } | ||
1454 | } | ||
1455 | |||
1456 | /* | ||
1457 | * Hardware Register Values | ||
1458 | */ | ||
1459 | |||
1460 | par->bplcon0 = BPC0_COLOR | bplpixmode[clk_shift]; | ||
1461 | if (!IS_OCS) | ||
1462 | par->bplcon0 |= BPC0_ECSENA; | ||
1463 | if (par->bpp == 8) | ||
1464 | par->bplcon0 |= BPC0_BPU3; | ||
1465 | else | ||
1466 | par->bplcon0 |= par->bpp << 12; | ||
1467 | if (var->nonstd == FB_NONSTD_HAM) | ||
1468 | par->bplcon0 |= BPC0_HAM; | ||
1469 | if (var->sync & FB_SYNC_EXT) | ||
1470 | par->bplcon0 |= BPC0_ERSY; | ||
1471 | |||
1472 | if (IS_AGA) | ||
1473 | par->fmode = bplfetchmode[maxfmode]; | ||
1474 | |||
1475 | switch (par->vmode & FB_VMODE_MASK) { | ||
1476 | case FB_VMODE_INTERLACED: | ||
1477 | par->bplcon0 |= BPC0_LACE; | ||
1478 | break; | ||
1479 | case FB_VMODE_DOUBLE: | ||
1480 | if (IS_AGA) | ||
1481 | par->fmode |= FMODE_SSCAN2 | FMODE_BSCAN2; | ||
1482 | break; | ||
1483 | } | ||
1484 | |||
1485 | if (!((par->vmode ^ var->vmode) & FB_VMODE_YWRAP)) { | ||
1486 | par->xoffset = var->xoffset; | ||
1487 | par->yoffset = var->yoffset; | ||
1488 | if (par->vmode & FB_VMODE_YWRAP) { | ||
1489 | if (par->xoffset || par->yoffset < 0 || | ||
1490 | par->yoffset >= par->vyres) | ||
1491 | par->xoffset = par->yoffset = 0; | ||
1492 | } else { | ||
1493 | if (par->xoffset < 0 || | ||
1494 | par->xoffset > upx(16 << maxfmode, par->vxres - par->xres) || | ||
1495 | par->yoffset < 0 || par->yoffset > par->vyres - par->yres) | ||
1496 | par->xoffset = par->yoffset = 0; | ||
1497 | } | ||
1498 | } else | ||
1499 | par->xoffset = par->yoffset = 0; | ||
1500 | |||
1501 | par->crsr.crsr_x = par->crsr.crsr_y = 0; | ||
1502 | par->crsr.spot_x = par->crsr.spot_y = 0; | ||
1503 | par->crsr.height = par->crsr.width = 0; | ||
1504 | |||
1505 | return 0; | ||
1506 | } | ||
1507 | |||
1508 | /* | ||
1509 | * Fill the `var' structure based on the values in `par' and maybe | ||
1510 | * other values read out of the hardware. | ||
1511 | */ | ||
1512 | |||
1513 | static void ami_encode_var(struct fb_var_screeninfo *var, | ||
1514 | struct amifb_par *par) | ||
1515 | { | ||
1516 | u_short clk_shift, line_shift; | ||
1517 | |||
1518 | memset(var, 0, sizeof(struct fb_var_screeninfo)); | ||
1519 | |||
1520 | clk_shift = par->clk_shift; | ||
1521 | line_shift = par->line_shift; | ||
1522 | |||
1523 | var->xres = par->xres; | ||
1524 | var->yres = par->yres; | ||
1525 | var->xres_virtual = par->vxres; | ||
1526 | var->yres_virtual = par->vyres; | ||
1527 | var->xoffset = par->xoffset; | ||
1528 | var->yoffset = par->yoffset; | ||
1529 | |||
1530 | var->bits_per_pixel = par->bpp; | ||
1531 | var->grayscale = 0; | ||
1532 | |||
1533 | var->red.offset = 0; | ||
1534 | var->red.msb_right = 0; | ||
1535 | var->red.length = par->bpp; | ||
1536 | if (par->bplcon0 & BPC0_HAM) | ||
1537 | var->red.length -= 2; | ||
1538 | var->blue = var->green = var->red; | ||
1539 | var->transp.offset = 0; | ||
1540 | var->transp.length = 0; | ||
1541 | var->transp.msb_right = 0; | ||
1542 | |||
1543 | if (par->bplcon0 & BPC0_HAM) | ||
1544 | var->nonstd = FB_NONSTD_HAM; | ||
1545 | else | ||
1546 | var->nonstd = 0; | ||
1547 | var->activate = 0; | ||
1548 | |||
1549 | var->height = -1; | ||
1550 | var->width = -1; | ||
1551 | |||
1552 | var->pixclock = pixclock[clk_shift]; | ||
1553 | |||
1554 | if (IS_AGA && par->fmode & FMODE_BSCAN2) | ||
1555 | var->vmode = FB_VMODE_DOUBLE; | ||
1556 | else if (par->bplcon0 & BPC0_LACE) | ||
1557 | var->vmode = FB_VMODE_INTERLACED; | ||
1558 | else | ||
1559 | var->vmode = FB_VMODE_NONINTERLACED; | ||
1560 | |||
1561 | if (!IS_OCS && par->beamcon0 & BMC0_VARBEAMEN) { | ||
1562 | var->hsync_len = (par->hsstop - par->hsstrt)>>clk_shift; | ||
1563 | var->right_margin = par->hsstrt>>clk_shift; | ||
1564 | var->left_margin = (par->htotal>>clk_shift) - var->xres - var->right_margin - var->hsync_len; | ||
1565 | var->vsync_len = (par->vsstop - par->vsstrt)>>line_shift; | ||
1566 | var->lower_margin = par->vsstrt>>line_shift; | ||
1567 | var->upper_margin = (par->vtotal>>line_shift) - var->yres - var->lower_margin - var->vsync_len; | ||
1568 | var->sync = 0; | ||
1569 | if (par->beamcon0 & BMC0_HSYTRUE) | ||
1570 | var->sync |= FB_SYNC_HOR_HIGH_ACT; | ||
1571 | if (par->beamcon0 & BMC0_VSYTRUE) | ||
1572 | var->sync |= FB_SYNC_VERT_HIGH_ACT; | ||
1573 | if (par->beamcon0 & BMC0_CSYTRUE) | ||
1574 | var->sync |= FB_SYNC_COMP_HIGH_ACT; | ||
1575 | } else { | ||
1576 | var->sync = FB_SYNC_BROADCAST; | ||
1577 | var->hsync_len = (152>>clk_shift) + mod4(par->diwstop_h); | ||
1578 | var->right_margin = ((par->htotal - down4(par->diwstop_h))>>clk_shift) + var->hsync_len; | ||
1579 | var->left_margin = (par->htotal>>clk_shift) - var->xres - var->right_margin - var->hsync_len; | ||
1580 | var->vsync_len = 4>>line_shift; | ||
1581 | var->lower_margin = ((par->vtotal - par->diwstop_v)>>line_shift) + var->vsync_len; | ||
1582 | var->upper_margin = (((par->vtotal - 2)>>line_shift) + 1) - var->yres - | ||
1583 | var->lower_margin - var->vsync_len; | ||
1584 | } | ||
1585 | |||
1586 | if (par->bplcon0 & BPC0_ERSY) | ||
1587 | var->sync |= FB_SYNC_EXT; | ||
1588 | if (par->vmode & FB_VMODE_YWRAP) | ||
1589 | var->vmode |= FB_VMODE_YWRAP; | ||
1590 | } | ||
1591 | |||
1592 | |||
1593 | /* | ||
1594 | * Update hardware | ||
1595 | */ | ||
1596 | |||
1597 | static void ami_update_par(struct fb_info *info) | ||
1598 | { | ||
1599 | struct amifb_par *par = info->par; | ||
1600 | short clk_shift, vshift, fstrt, fsize, fstop, fconst, shift, move, mod; | ||
1601 | |||
1602 | clk_shift = par->clk_shift; | ||
1603 | |||
1604 | if (!(par->vmode & FB_VMODE_SMOOTH_XPAN)) | ||
1605 | par->xoffset = upx(16 << maxfmode, par->xoffset); | ||
1606 | |||
1607 | fconst = 16 << maxfmode << clk_shift; | ||
1608 | vshift = modx(16 << maxfmode, par->xoffset); | ||
1609 | fstrt = par->diwstrt_h - (vshift << clk_shift) - 4; | ||
1610 | fsize = (par->xres + vshift) << clk_shift; | ||
1611 | shift = modx(fconst, fstrt); | ||
1612 | move = downx(2 << maxfmode, div8(par->xoffset)); | ||
1613 | if (maxfmode + clk_shift > 1) { | ||
1614 | fstrt = downx(fconst, fstrt) - 64; | ||
1615 | fsize = upx(fconst, fsize); | ||
1616 | fstop = fstrt + fsize - fconst; | ||
1617 | } else { | ||
1618 | mod = fstrt = downx(fconst, fstrt) - fconst; | ||
1619 | fstop = fstrt + upx(fconst, fsize) - 64; | ||
1620 | fsize = up64(fsize); | ||
1621 | fstrt = fstop - fsize + 64; | ||
1622 | if (fstrt < min_fstrt) { | ||
1623 | fstop += min_fstrt - fstrt; | ||
1624 | fstrt = min_fstrt; | ||
1625 | } | ||
1626 | move = move - div8((mod - fstrt)>>clk_shift); | ||
1627 | } | ||
1628 | mod = par->next_line - div8(fsize>>clk_shift); | ||
1629 | par->ddfstrt = fstrt; | ||
1630 | par->ddfstop = fstop; | ||
1631 | par->bplcon1 = hscroll2hw(shift); | ||
1632 | par->bpl2mod = mod; | ||
1633 | if (par->bplcon0 & BPC0_LACE) | ||
1634 | par->bpl2mod += par->next_line; | ||
1635 | if (IS_AGA && (par->fmode & FMODE_BSCAN2)) | ||
1636 | par->bpl1mod = -div8(fsize>>clk_shift); | ||
1637 | else | ||
1638 | par->bpl1mod = par->bpl2mod; | ||
1639 | |||
1640 | if (par->yoffset) { | ||
1641 | par->bplpt0 = info->fix.smem_start + | ||
1642 | par->next_line * par->yoffset + move; | ||
1643 | if (par->vmode & FB_VMODE_YWRAP) { | ||
1644 | if (par->yoffset > par->vyres - par->yres) { | ||
1645 | par->bplpt0wrap = info->fix.smem_start + move; | ||
1646 | if (par->bplcon0 & BPC0_LACE && | ||
1647 | mod2(par->diwstrt_v + par->vyres - | ||
1648 | par->yoffset)) | ||
1649 | par->bplpt0wrap += par->next_line; | ||
1650 | } | ||
1651 | } | ||
1652 | } else | ||
1653 | par->bplpt0 = info->fix.smem_start + move; | ||
1654 | |||
1655 | if (par->bplcon0 & BPC0_LACE && mod2(par->diwstrt_v)) | ||
1656 | par->bplpt0 += par->next_line; | ||
1657 | } | ||
1658 | |||
1659 | |||
1660 | /* | ||
1661 | * Pan or Wrap the Display | ||
1662 | * | ||
1663 | * This call looks only at xoffset, yoffset and the FB_VMODE_YWRAP flag | ||
1664 | * in `var'. | ||
1665 | */ | ||
1666 | |||
1667 | static void ami_pan_var(struct fb_var_screeninfo *var, struct fb_info *info) | ||
1668 | { | ||
1669 | struct amifb_par *par = info->par; | ||
1670 | |||
1671 | par->xoffset = var->xoffset; | ||
1672 | par->yoffset = var->yoffset; | ||
1673 | if (var->vmode & FB_VMODE_YWRAP) | ||
1674 | par->vmode |= FB_VMODE_YWRAP; | ||
1675 | else | ||
1676 | par->vmode &= ~FB_VMODE_YWRAP; | ||
1677 | |||
1678 | do_vmode_pan = 0; | ||
1679 | ami_update_par(info); | ||
1680 | do_vmode_pan = 1; | ||
1681 | } | ||
1682 | |||
1683 | |||
1684 | static void ami_update_display(const struct amifb_par *par) | ||
1685 | { | ||
1686 | custom.bplcon1 = par->bplcon1; | ||
1687 | custom.bpl1mod = par->bpl1mod; | ||
1688 | custom.bpl2mod = par->bpl2mod; | ||
1689 | custom.ddfstrt = ddfstrt2hw(par->ddfstrt); | ||
1690 | custom.ddfstop = ddfstop2hw(par->ddfstop); | ||
1691 | } | ||
1692 | |||
1693 | /* | ||
1694 | * Change the video mode (called by VBlank interrupt) | ||
1695 | */ | ||
1696 | |||
1697 | static void ami_init_display(const struct amifb_par *par) | ||
1698 | { | ||
1699 | int i; | ||
1700 | |||
1701 | custom.bplcon0 = par->bplcon0 & ~BPC0_LACE; | ||
1702 | custom.bplcon2 = (IS_OCS ? 0 : BPC2_KILLEHB) | BPC2_PF2P2 | BPC2_PF1P2; | ||
1703 | if (!IS_OCS) { | ||
1704 | custom.bplcon3 = par->bplcon3; | ||
1705 | if (IS_AGA) | ||
1706 | custom.bplcon4 = BPC4_ESPRM4 | BPC4_OSPRM4; | ||
1707 | if (par->beamcon0 & BMC0_VARBEAMEN) { | ||
1708 | custom.htotal = htotal2hw(par->htotal); | ||
1709 | custom.hbstrt = hbstrt2hw(par->hbstrt); | ||
1710 | custom.hbstop = hbstop2hw(par->hbstop); | ||
1711 | custom.hsstrt = hsstrt2hw(par->hsstrt); | ||
1712 | custom.hsstop = hsstop2hw(par->hsstop); | ||
1713 | custom.hcenter = hcenter2hw(par->hcenter); | ||
1714 | custom.vtotal = vtotal2hw(par->vtotal); | ||
1715 | custom.vbstrt = vbstrt2hw(par->vbstrt); | ||
1716 | custom.vbstop = vbstop2hw(par->vbstop); | ||
1717 | custom.vsstrt = vsstrt2hw(par->vsstrt); | ||
1718 | custom.vsstop = vsstop2hw(par->vsstop); | ||
1719 | } | ||
1720 | } | ||
1721 | if (!IS_OCS || par->hsstop) | ||
1722 | custom.beamcon0 = par->beamcon0; | ||
1723 | if (IS_AGA) | ||
1724 | custom.fmode = par->fmode; | ||
1725 | |||
1726 | /* | ||
1727 | * The minimum period for audio depends on htotal | ||
1728 | */ | ||
1729 | |||
1730 | amiga_audio_min_period = div16(par->htotal); | ||
1731 | |||
1732 | is_lace = par->bplcon0 & BPC0_LACE ? 1 : 0; | ||
1733 | #if 1 | ||
1734 | if (is_lace) { | ||
1735 | i = custom.vposr >> 15; | ||
1736 | } else { | ||
1737 | custom.vposw = custom.vposr | 0x8000; | ||
1738 | i = 1; | ||
1739 | } | ||
1740 | #else | ||
1741 | i = 1; | ||
1742 | custom.vposw = custom.vposr | 0x8000; | ||
1743 | #endif | ||
1744 | custom.cop2lc = (u_short *)ZTWO_PADDR(copdisplay.list[currentcop][i]); | ||
1745 | } | ||
1746 | |||
1747 | /* | ||
1748 | * (Un)Blank the screen (called by VBlank interrupt) | ||
1749 | */ | ||
1750 | |||
1751 | static void ami_do_blank(const struct amifb_par *par) | ||
1752 | { | ||
1753 | #if defined(CONFIG_FB_AMIGA_AGA) | ||
1754 | u_short bplcon3 = par->bplcon3; | ||
1755 | #endif | ||
1756 | u_char red, green, blue; | ||
1757 | |||
1758 | if (do_blank > 0) { | ||
1759 | custom.dmacon = DMAF_RASTER | DMAF_SPRITE; | ||
1760 | red = green = blue = 0; | ||
1761 | if (!IS_OCS && do_blank > 1) { | ||
1762 | switch (do_blank) { | ||
1763 | case FB_BLANK_VSYNC_SUSPEND: | ||
1764 | custom.hsstrt = hsstrt2hw(par->hsstrt); | ||
1765 | custom.hsstop = hsstop2hw(par->hsstop); | ||
1766 | custom.vsstrt = vsstrt2hw(par->vtotal + 4); | ||
1767 | custom.vsstop = vsstop2hw(par->vtotal + 4); | ||
1768 | break; | ||
1769 | case FB_BLANK_HSYNC_SUSPEND: | ||
1770 | custom.hsstrt = hsstrt2hw(par->htotal + 16); | ||
1771 | custom.hsstop = hsstop2hw(par->htotal + 16); | ||
1772 | custom.vsstrt = vsstrt2hw(par->vsstrt); | ||
1773 | custom.vsstop = vsstrt2hw(par->vsstop); | ||
1774 | break; | ||
1775 | case FB_BLANK_POWERDOWN: | ||
1776 | custom.hsstrt = hsstrt2hw(par->htotal + 16); | ||
1777 | custom.hsstop = hsstop2hw(par->htotal + 16); | ||
1778 | custom.vsstrt = vsstrt2hw(par->vtotal + 4); | ||
1779 | custom.vsstop = vsstop2hw(par->vtotal + 4); | ||
1780 | break; | ||
1781 | } | ||
1782 | if (!(par->beamcon0 & BMC0_VARBEAMEN)) { | ||
1783 | custom.htotal = htotal2hw(par->htotal); | ||
1784 | custom.vtotal = vtotal2hw(par->vtotal); | ||
1785 | custom.beamcon0 = BMC0_HARDDIS | BMC0_VARBEAMEN | | ||
1786 | BMC0_VARVSYEN | BMC0_VARHSYEN | BMC0_VARCSYEN; | ||
1787 | } | ||
1788 | } | ||
1789 | } else { | ||
1790 | custom.dmacon = DMAF_SETCLR | DMAF_RASTER | DMAF_SPRITE; | ||
1791 | red = red0; | ||
1792 | green = green0; | ||
1793 | blue = blue0; | ||
1794 | if (!IS_OCS) { | ||
1795 | custom.hsstrt = hsstrt2hw(par->hsstrt); | ||
1796 | custom.hsstop = hsstop2hw(par->hsstop); | ||
1797 | custom.vsstrt = vsstrt2hw(par->vsstrt); | ||
1798 | custom.vsstop = vsstop2hw(par->vsstop); | ||
1799 | custom.beamcon0 = par->beamcon0; | ||
1800 | } | ||
1801 | } | ||
1802 | #if defined(CONFIG_FB_AMIGA_AGA) | ||
1803 | if (IS_AGA) { | ||
1804 | custom.bplcon3 = bplcon3; | ||
1805 | custom.color[0] = rgb2hw8_high(red, green, blue); | ||
1806 | custom.bplcon3 = bplcon3 | BPC3_LOCT; | ||
1807 | custom.color[0] = rgb2hw8_low(red, green, blue); | ||
1808 | custom.bplcon3 = bplcon3; | ||
1809 | } else | ||
1810 | #endif | ||
1811 | #if defined(CONFIG_FB_AMIGA_ECS) | ||
1812 | if (par->bplcon0 & BPC0_SHRES) { | ||
1813 | u_short color, mask; | ||
1814 | int i; | ||
1815 | |||
1816 | mask = 0x3333; | ||
1817 | color = rgb2hw2(red, green, blue); | ||
1818 | for (i = 12; i >= 0; i -= 4) | ||
1819 | custom.color[i] = ecs_palette[i] = (ecs_palette[i] & mask) | color; | ||
1820 | mask <<= 2; color >>= 2; | ||
1821 | for (i = 3; i >= 0; i--) | ||
1822 | custom.color[i] = ecs_palette[i] = (ecs_palette[i] & mask) | color; | ||
1823 | } else | ||
1824 | #endif | ||
1825 | custom.color[0] = rgb2hw4(red, green, blue); | ||
1826 | is_blanked = do_blank > 0 ? do_blank : 0; | ||
1827 | } | ||
1828 | |||
1829 | static int ami_get_fix_cursorinfo(struct fb_fix_cursorinfo *fix, | ||
1830 | const struct amifb_par *par) | ||
1831 | { | ||
1832 | fix->crsr_width = fix->crsr_xsize = par->crsr.width; | ||
1833 | fix->crsr_height = fix->crsr_ysize = par->crsr.height; | ||
1834 | fix->crsr_color1 = 17; | ||
1835 | fix->crsr_color2 = 18; | ||
1836 | return 0; | ||
1837 | } | ||
1838 | |||
1839 | static int ami_get_var_cursorinfo(struct fb_var_cursorinfo *var, | ||
1840 | u_char __user *data, | ||
1841 | const struct amifb_par *par) | ||
1842 | { | ||
1843 | register u_short *lspr, *sspr; | ||
1844 | #ifdef __mc68000__ | ||
1845 | register u_long datawords asm ("d2"); | ||
1846 | #else | ||
1847 | register u_long datawords; | ||
1848 | #endif | ||
1849 | register short delta; | ||
1850 | register u_char color; | ||
1851 | short height, width, bits, words; | ||
1852 | int size, alloc; | ||
1853 | |||
1854 | size = par->crsr.height * par->crsr.width; | ||
1855 | alloc = var->height * var->width; | ||
1856 | var->height = par->crsr.height; | ||
1857 | var->width = par->crsr.width; | ||
1858 | var->xspot = par->crsr.spot_x; | ||
1859 | var->yspot = par->crsr.spot_y; | ||
1860 | if (size > var->height * var->width) | ||
1861 | return -ENAMETOOLONG; | ||
1862 | if (!access_ok(VERIFY_WRITE, data, size)) | ||
1863 | return -EFAULT; | ||
1864 | delta = 1 << par->crsr.fmode; | ||
1865 | lspr = lofsprite + (delta << 1); | ||
1866 | if (par->bplcon0 & BPC0_LACE) | ||
1867 | sspr = shfsprite + (delta << 1); | ||
1868 | else | ||
1869 | sspr = NULL; | ||
1870 | for (height = (short)var->height - 1; height >= 0; height--) { | ||
1871 | bits = 0; words = delta; datawords = 0; | ||
1872 | for (width = (short)var->width - 1; width >= 0; width--) { | ||
1873 | if (bits == 0) { | ||
1874 | bits = 16; --words; | ||
1875 | #ifdef __mc68000__ | ||
1876 | asm volatile ("movew %1@(%3:w:2),%0 ; swap %0 ; movew %1@+,%0" | ||
1877 | : "=d" (datawords), "=a" (lspr) : "1" (lspr), "d" (delta)); | ||
1878 | #else | ||
1879 | datawords = (*(lspr + delta) << 16) | (*lspr++); | ||
1880 | #endif | ||
1881 | } | ||
1882 | --bits; | ||
1883 | #ifdef __mc68000__ | ||
1884 | asm volatile ( | ||
1885 | "clrb %0 ; swap %1 ; lslw #1,%1 ; roxlb #1,%0 ; " | ||
1886 | "swap %1 ; lslw #1,%1 ; roxlb #1,%0" | ||
1887 | : "=d" (color), "=d" (datawords) : "1" (datawords)); | ||
1888 | #else | ||
1889 | color = (((datawords >> 30) & 2) | ||
1890 | | ((datawords >> 15) & 1)); | ||
1891 | datawords <<= 1; | ||
1892 | #endif | ||
1893 | put_user(color, data++); | ||
1894 | } | ||
1895 | if (bits > 0) { | ||
1896 | --words; ++lspr; | ||
1897 | } | ||
1898 | while (--words >= 0) | ||
1899 | ++lspr; | ||
1900 | #ifdef __mc68000__ | ||
1901 | asm volatile ("lea %0@(%4:w:2),%0 ; tstl %1 ; jeq 1f ; exg %0,%1\n1:" | ||
1902 | : "=a" (lspr), "=a" (sspr) : "0" (lspr), "1" (sspr), "d" (delta)); | ||
1903 | #else | ||
1904 | lspr += delta; | ||
1905 | if (sspr) { | ||
1906 | u_short *tmp = lspr; | ||
1907 | lspr = sspr; | ||
1908 | sspr = tmp; | ||
1909 | } | ||
1910 | #endif | ||
1911 | } | ||
1912 | return 0; | ||
1913 | } | ||
1914 | |||
1915 | static int ami_set_var_cursorinfo(struct fb_var_cursorinfo *var, | ||
1916 | u_char __user *data, struct amifb_par *par) | ||
1917 | { | ||
1918 | register u_short *lspr, *sspr; | ||
1919 | #ifdef __mc68000__ | ||
1920 | register u_long datawords asm ("d2"); | ||
1921 | #else | ||
1922 | register u_long datawords; | ||
1923 | #endif | ||
1924 | register short delta; | ||
1925 | u_short fmode; | ||
1926 | short height, width, bits, words; | ||
1927 | |||
1928 | if (!var->width) | ||
1929 | return -EINVAL; | ||
1930 | else if (var->width <= 16) | ||
1931 | fmode = TAG_FMODE_1; | ||
1932 | else if (var->width <= 32) | ||
1933 | fmode = TAG_FMODE_2; | ||
1934 | else if (var->width <= 64) | ||
1935 | fmode = TAG_FMODE_4; | ||
1936 | else | ||
1937 | return -EINVAL; | ||
1938 | if (fmode > maxfmode) | ||
1939 | return -EINVAL; | ||
1940 | if (!var->height) | ||
1941 | return -EINVAL; | ||
1942 | if (!access_ok(VERIFY_READ, data, var->width * var->height)) | ||
1943 | return -EFAULT; | ||
1944 | delta = 1 << fmode; | ||
1945 | lofsprite = shfsprite = (u_short *)spritememory; | ||
1946 | lspr = lofsprite + (delta << 1); | ||
1947 | if (par->bplcon0 & BPC0_LACE) { | ||
1948 | if (((var->height + 4) << fmode << 2) > SPRITEMEMSIZE) | ||
1949 | return -EINVAL; | ||
1950 | memset(lspr, 0, (var->height + 4) << fmode << 2); | ||
1951 | shfsprite += ((var->height + 5)&-2) << fmode; | ||
1952 | sspr = shfsprite + (delta << 1); | ||
1953 | } else { | ||
1954 | if (((var->height + 2) << fmode << 2) > SPRITEMEMSIZE) | ||
1955 | return -EINVAL; | ||
1956 | memset(lspr, 0, (var->height + 2) << fmode << 2); | ||
1957 | sspr = NULL; | ||
1958 | } | ||
1959 | for (height = (short)var->height - 1; height >= 0; height--) { | ||
1960 | bits = 16; words = delta; datawords = 0; | ||
1961 | for (width = (short)var->width - 1; width >= 0; width--) { | ||
1962 | unsigned long tdata = 0; | ||
1963 | get_user(tdata, data); | ||
1964 | data++; | ||
1965 | #ifdef __mc68000__ | ||
1966 | asm volatile ( | ||
1967 | "lsrb #1,%2 ; roxlw #1,%0 ; swap %0 ; " | ||
1968 | "lsrb #1,%2 ; roxlw #1,%0 ; swap %0" | ||
1969 | : "=d" (datawords) | ||
1970 | : "0" (datawords), "d" (tdata)); | ||
1971 | #else | ||
1972 | datawords = ((datawords << 1) & 0xfffefffe); | ||
1973 | datawords |= tdata & 1; | ||
1974 | datawords |= (tdata & 2) << (16 - 1); | ||
1975 | #endif | ||
1976 | if (--bits == 0) { | ||
1977 | bits = 16; --words; | ||
1978 | #ifdef __mc68000__ | ||
1979 | asm volatile ("swap %2 ; movew %2,%0@(%3:w:2) ; swap %2 ; movew %2,%0@+" | ||
1980 | : "=a" (lspr) : "0" (lspr), "d" (datawords), "d" (delta)); | ||
1981 | #else | ||
1982 | *(lspr + delta) = (u_short) (datawords >> 16); | ||
1983 | *lspr++ = (u_short) (datawords & 0xffff); | ||
1984 | #endif | ||
1985 | } | ||
1986 | } | ||
1987 | if (bits < 16) { | ||
1988 | --words; | ||
1989 | #ifdef __mc68000__ | ||
1990 | asm volatile ( | ||
1991 | "swap %2 ; lslw %4,%2 ; movew %2,%0@(%3:w:2) ; " | ||
1992 | "swap %2 ; lslw %4,%2 ; movew %2,%0@+" | ||
1993 | : "=a" (lspr) : "0" (lspr), "d" (datawords), "d" (delta), "d" (bits)); | ||
1994 | #else | ||
1995 | *(lspr + delta) = (u_short) (datawords >> (16 + bits)); | ||
1996 | *lspr++ = (u_short) ((datawords & 0x0000ffff) >> bits); | ||
1997 | #endif | ||
1998 | } | ||
1999 | while (--words >= 0) { | ||
2000 | #ifdef __mc68000__ | ||
2001 | asm volatile ("moveql #0,%%d0 ; movew %%d0,%0@(%2:w:2) ; movew %%d0,%0@+" | ||
2002 | : "=a" (lspr) : "0" (lspr), "d" (delta) : "d0"); | ||
2003 | #else | ||
2004 | *(lspr + delta) = 0; | ||
2005 | *lspr++ = 0; | ||
2006 | #endif | ||
2007 | } | ||
2008 | #ifdef __mc68000__ | ||
2009 | asm volatile ("lea %0@(%4:w:2),%0 ; tstl %1 ; jeq 1f ; exg %0,%1\n1:" | ||
2010 | : "=a" (lspr), "=a" (sspr) : "0" (lspr), "1" (sspr), "d" (delta)); | ||
2011 | #else | ||
2012 | lspr += delta; | ||
2013 | if (sspr) { | ||
2014 | u_short *tmp = lspr; | ||
2015 | lspr = sspr; | ||
2016 | sspr = tmp; | ||
2017 | } | ||
2018 | #endif | ||
2019 | } | ||
2020 | par->crsr.height = var->height; | ||
2021 | par->crsr.width = var->width; | ||
2022 | par->crsr.spot_x = var->xspot; | ||
2023 | par->crsr.spot_y = var->yspot; | ||
2024 | par->crsr.fmode = fmode; | ||
2025 | if (IS_AGA) { | ||
2026 | par->fmode &= ~(FMODE_SPAGEM | FMODE_SPR32); | ||
2027 | par->fmode |= sprfetchmode[fmode]; | ||
2028 | custom.fmode = par->fmode; | ||
2029 | } | ||
2030 | return 0; | ||
2031 | } | ||
2032 | |||
2033 | static int ami_get_cursorstate(struct fb_cursorstate *state, | ||
2034 | const struct amifb_par *par) | ||
2035 | { | ||
2036 | state->xoffset = par->crsr.crsr_x; | ||
2037 | state->yoffset = par->crsr.crsr_y; | ||
2038 | state->mode = cursormode; | ||
2039 | return 0; | ||
2040 | } | ||
2041 | |||
2042 | static int ami_set_cursorstate(struct fb_cursorstate *state, | ||
2043 | struct amifb_par *par) | ||
2044 | { | ||
2045 | par->crsr.crsr_x = state->xoffset; | ||
2046 | par->crsr.crsr_y = state->yoffset; | ||
2047 | if ((cursormode = state->mode) == FB_CURSOR_OFF) | ||
2048 | cursorstate = -1; | ||
2049 | do_cursor = 1; | ||
2050 | return 0; | ||
2051 | } | ||
2052 | |||
2053 | static void ami_set_sprite(const struct amifb_par *par) | ||
2054 | { | ||
2055 | copins *copl, *cops; | ||
2056 | u_short hs, vs, ve; | ||
2057 | u_long pl, ps, pt; | ||
2058 | short mx, my; | ||
2059 | |||
2060 | cops = copdisplay.list[currentcop][0]; | ||
2061 | copl = copdisplay.list[currentcop][1]; | ||
2062 | ps = pl = ZTWO_PADDR(dummysprite); | ||
2063 | mx = par->crsr.crsr_x - par->crsr.spot_x; | ||
2064 | my = par->crsr.crsr_y - par->crsr.spot_y; | ||
2065 | if (!(par->vmode & FB_VMODE_YWRAP)) { | ||
2066 | mx -= par->xoffset; | ||
2067 | my -= par->yoffset; | ||
2068 | } | ||
2069 | if (!is_blanked && cursorstate > 0 && par->crsr.height > 0 && | ||
2070 | mx > -(short)par->crsr.width && mx < par->xres && | ||
2071 | my > -(short)par->crsr.height && my < par->yres) { | ||
2072 | pl = ZTWO_PADDR(lofsprite); | ||
2073 | hs = par->diwstrt_h + (mx << par->clk_shift) - 4; | ||
2074 | vs = par->diwstrt_v + (my << par->line_shift); | ||
2075 | ve = vs + (par->crsr.height << par->line_shift); | ||
2076 | if (par->bplcon0 & BPC0_LACE) { | ||
2077 | ps = ZTWO_PADDR(shfsprite); | ||
2078 | lofsprite[0] = spr2hw_pos(vs, hs); | ||
2079 | shfsprite[0] = spr2hw_pos(vs + 1, hs); | ||
2080 | if (mod2(vs)) { | ||
2081 | lofsprite[1 << par->crsr.fmode] = spr2hw_ctl(vs, hs, ve); | ||
2082 | shfsprite[1 << par->crsr.fmode] = spr2hw_ctl(vs + 1, hs, ve + 1); | ||
2083 | pt = pl; pl = ps; ps = pt; | ||
2084 | } else { | ||
2085 | lofsprite[1 << par->crsr.fmode] = spr2hw_ctl(vs, hs, ve + 1); | ||
2086 | shfsprite[1 << par->crsr.fmode] = spr2hw_ctl(vs + 1, hs, ve); | ||
2087 | } | ||
2088 | } else { | ||
2089 | lofsprite[0] = spr2hw_pos(vs, hs) | (IS_AGA && (par->fmode & FMODE_BSCAN2) ? 0x80 : 0); | ||
2090 | lofsprite[1 << par->crsr.fmode] = spr2hw_ctl(vs, hs, ve); | ||
2091 | } | ||
2092 | } | ||
2093 | copl[cop_spr0ptrh].w[1] = highw(pl); | ||
2094 | copl[cop_spr0ptrl].w[1] = loww(pl); | ||
2095 | if (par->bplcon0 & BPC0_LACE) { | ||
2096 | cops[cop_spr0ptrh].w[1] = highw(ps); | ||
2097 | cops[cop_spr0ptrl].w[1] = loww(ps); | ||
2098 | } | ||
2099 | } | ||
2100 | |||
2101 | |||
2102 | /* | ||
2103 | * Initialise the Copper Initialisation List | ||
2104 | */ | ||
2105 | |||
2106 | static void __init ami_init_copper(void) | ||
2107 | { | ||
2108 | copins *cop = copdisplay.init; | ||
2109 | u_long p; | ||
2110 | int i; | ||
2111 | |||
2112 | if (!IS_OCS) { | ||
2113 | (cop++)->l = CMOVE(BPC0_COLOR | BPC0_SHRES | BPC0_ECSENA, bplcon0); | ||
2114 | (cop++)->l = CMOVE(0x0181, diwstrt); | ||
2115 | (cop++)->l = CMOVE(0x0281, diwstop); | ||
2116 | (cop++)->l = CMOVE(0x0000, diwhigh); | ||
2117 | } else | ||
2118 | (cop++)->l = CMOVE(BPC0_COLOR, bplcon0); | ||
2119 | p = ZTWO_PADDR(dummysprite); | ||
2120 | for (i = 0; i < 8; i++) { | ||
2121 | (cop++)->l = CMOVE(0, spr[i].pos); | ||
2122 | (cop++)->l = CMOVE(highw(p), sprpt[i]); | ||
2123 | (cop++)->l = CMOVE2(loww(p), sprpt[i]); | ||
2124 | } | ||
2125 | |||
2126 | (cop++)->l = CMOVE(IF_SETCLR | IF_COPER, intreq); | ||
2127 | copdisplay.wait = cop; | ||
2128 | (cop++)->l = CEND; | ||
2129 | (cop++)->l = CMOVE(0, copjmp2); | ||
2130 | cop->l = CEND; | ||
2131 | |||
2132 | custom.cop1lc = (u_short *)ZTWO_PADDR(copdisplay.init); | ||
2133 | custom.copjmp1 = 0; | ||
2134 | } | ||
2135 | |||
2136 | static void ami_reinit_copper(const struct amifb_par *par) | ||
2137 | { | ||
2138 | copdisplay.init[cip_bplcon0].w[1] = ~(BPC0_BPU3 | BPC0_BPU2 | BPC0_BPU1 | BPC0_BPU0) & par->bplcon0; | ||
2139 | copdisplay.wait->l = CWAIT(32, par->diwstrt_v - 4); | ||
2140 | } | ||
2141 | |||
2142 | |||
2143 | /* | ||
2144 | * Rebuild the Copper List | ||
2145 | * | ||
2146 | * We only change the things that are not static | ||
2147 | */ | ||
2148 | |||
2149 | static void ami_rebuild_copper(const struct amifb_par *par) | ||
2150 | { | ||
2151 | copins *copl, *cops; | ||
2152 | u_short line, h_end1, h_end2; | ||
2153 | short i; | ||
2154 | u_long p; | ||
2155 | |||
2156 | if (IS_AGA && maxfmode + par->clk_shift == 0) | ||
2157 | h_end1 = par->diwstrt_h - 64; | ||
2158 | else | ||
2159 | h_end1 = par->htotal - 32; | ||
2160 | h_end2 = par->ddfstop + 64; | ||
2161 | |||
2162 | ami_set_sprite(par); | ||
2163 | |||
2164 | copl = copdisplay.rebuild[1]; | ||
2165 | p = par->bplpt0; | ||
2166 | if (par->vmode & FB_VMODE_YWRAP) { | ||
2167 | if ((par->vyres - par->yoffset) != 1 || !mod2(par->diwstrt_v)) { | ||
2168 | if (par->yoffset > par->vyres - par->yres) { | ||
2169 | for (i = 0; i < (short)par->bpp; i++, p += par->next_plane) { | ||
2170 | (copl++)->l = CMOVE(highw(p), bplpt[i]); | ||
2171 | (copl++)->l = CMOVE2(loww(p), bplpt[i]); | ||
2172 | } | ||
2173 | line = par->diwstrt_v + ((par->vyres - par->yoffset) << par->line_shift) - 1; | ||
2174 | while (line >= 512) { | ||
2175 | (copl++)->l = CWAIT(h_end1, 510); | ||
2176 | line -= 512; | ||
2177 | } | ||
2178 | if (line >= 510 && IS_AGA && maxfmode + par->clk_shift == 0) | ||
2179 | (copl++)->l = CWAIT(h_end1, line); | ||
2180 | else | ||
2181 | (copl++)->l = CWAIT(h_end2, line); | ||
2182 | p = par->bplpt0wrap; | ||
2183 | } | ||
2184 | } else | ||
2185 | p = par->bplpt0wrap; | ||
2186 | } | ||
2187 | for (i = 0; i < (short)par->bpp; i++, p += par->next_plane) { | ||
2188 | (copl++)->l = CMOVE(highw(p), bplpt[i]); | ||
2189 | (copl++)->l = CMOVE2(loww(p), bplpt[i]); | ||
2190 | } | ||
2191 | copl->l = CEND; | ||
2192 | |||
2193 | if (par->bplcon0 & BPC0_LACE) { | ||
2194 | cops = copdisplay.rebuild[0]; | ||
2195 | p = par->bplpt0; | ||
2196 | if (mod2(par->diwstrt_v)) | ||
2197 | p -= par->next_line; | ||
2198 | else | ||
2199 | p += par->next_line; | ||
2200 | if (par->vmode & FB_VMODE_YWRAP) { | ||
2201 | if ((par->vyres - par->yoffset) != 1 || mod2(par->diwstrt_v)) { | ||
2202 | if (par->yoffset > par->vyres - par->yres + 1) { | ||
2203 | for (i = 0; i < (short)par->bpp; i++, p += par->next_plane) { | ||
2204 | (cops++)->l = CMOVE(highw(p), bplpt[i]); | ||
2205 | (cops++)->l = CMOVE2(loww(p), bplpt[i]); | ||
2206 | } | ||
2207 | line = par->diwstrt_v + ((par->vyres - par->yoffset) << par->line_shift) - 2; | ||
2208 | while (line >= 512) { | ||
2209 | (cops++)->l = CWAIT(h_end1, 510); | ||
2210 | line -= 512; | ||
2211 | } | ||
2212 | if (line > 510 && IS_AGA && maxfmode + par->clk_shift == 0) | ||
2213 | (cops++)->l = CWAIT(h_end1, line); | ||
2214 | else | ||
2215 | (cops++)->l = CWAIT(h_end2, line); | ||
2216 | p = par->bplpt0wrap; | ||
2217 | if (mod2(par->diwstrt_v + par->vyres - | ||
2218 | par->yoffset)) | ||
2219 | p -= par->next_line; | ||
2220 | else | ||
2221 | p += par->next_line; | ||
2222 | } | ||
2223 | } else | ||
2224 | p = par->bplpt0wrap - par->next_line; | ||
2225 | } | ||
2226 | for (i = 0; i < (short)par->bpp; i++, p += par->next_plane) { | ||
2227 | (cops++)->l = CMOVE(highw(p), bplpt[i]); | ||
2228 | (cops++)->l = CMOVE2(loww(p), bplpt[i]); | ||
2229 | } | ||
2230 | cops->l = CEND; | ||
2231 | } | ||
2232 | } | ||
2233 | |||
2234 | |||
2235 | /* | ||
2236 | * Build the Copper List | ||
2237 | */ | ||
2238 | |||
2239 | static void ami_build_copper(struct fb_info *info) | ||
2240 | { | ||
2241 | struct amifb_par *par = info->par; | ||
2242 | copins *copl, *cops; | ||
2243 | u_long p; | ||
2244 | |||
2245 | currentcop = 1 - currentcop; | ||
2246 | |||
2247 | copl = copdisplay.list[currentcop][1]; | ||
2248 | |||
2249 | (copl++)->l = CWAIT(0, 10); | ||
2250 | (copl++)->l = CMOVE(par->bplcon0, bplcon0); | ||
2251 | (copl++)->l = CMOVE(0, sprpt[0]); | ||
2252 | (copl++)->l = CMOVE2(0, sprpt[0]); | ||
2253 | |||
2254 | if (par->bplcon0 & BPC0_LACE) { | ||
2255 | cops = copdisplay.list[currentcop][0]; | ||
2256 | |||
2257 | (cops++)->l = CWAIT(0, 10); | ||
2258 | (cops++)->l = CMOVE(par->bplcon0, bplcon0); | ||
2259 | (cops++)->l = CMOVE(0, sprpt[0]); | ||
2260 | (cops++)->l = CMOVE2(0, sprpt[0]); | ||
2261 | |||
2262 | (copl++)->l = CMOVE(diwstrt2hw(par->diwstrt_h, par->diwstrt_v + 1), diwstrt); | ||
2263 | (copl++)->l = CMOVE(diwstop2hw(par->diwstop_h, par->diwstop_v + 1), diwstop); | ||
2264 | (cops++)->l = CMOVE(diwstrt2hw(par->diwstrt_h, par->diwstrt_v), diwstrt); | ||
2265 | (cops++)->l = CMOVE(diwstop2hw(par->diwstop_h, par->diwstop_v), diwstop); | ||
2266 | if (!IS_OCS) { | ||
2267 | (copl++)->l = CMOVE(diwhigh2hw(par->diwstrt_h, par->diwstrt_v + 1, | ||
2268 | par->diwstop_h, par->diwstop_v + 1), diwhigh); | ||
2269 | (cops++)->l = CMOVE(diwhigh2hw(par->diwstrt_h, par->diwstrt_v, | ||
2270 | par->diwstop_h, par->diwstop_v), diwhigh); | ||
2271 | #if 0 | ||
2272 | if (par->beamcon0 & BMC0_VARBEAMEN) { | ||
2273 | (copl++)->l = CMOVE(vtotal2hw(par->vtotal), vtotal); | ||
2274 | (copl++)->l = CMOVE(vbstrt2hw(par->vbstrt + 1), vbstrt); | ||
2275 | (copl++)->l = CMOVE(vbstop2hw(par->vbstop + 1), vbstop); | ||
2276 | (cops++)->l = CMOVE(vtotal2hw(par->vtotal), vtotal); | ||
2277 | (cops++)->l = CMOVE(vbstrt2hw(par->vbstrt), vbstrt); | ||
2278 | (cops++)->l = CMOVE(vbstop2hw(par->vbstop), vbstop); | ||
2279 | } | ||
2280 | #endif | ||
2281 | } | ||
2282 | p = ZTWO_PADDR(copdisplay.list[currentcop][0]); | ||
2283 | (copl++)->l = CMOVE(highw(p), cop2lc); | ||
2284 | (copl++)->l = CMOVE2(loww(p), cop2lc); | ||
2285 | p = ZTWO_PADDR(copdisplay.list[currentcop][1]); | ||
2286 | (cops++)->l = CMOVE(highw(p), cop2lc); | ||
2287 | (cops++)->l = CMOVE2(loww(p), cop2lc); | ||
2288 | copdisplay.rebuild[0] = cops; | ||
2289 | } else { | ||
2290 | (copl++)->l = CMOVE(diwstrt2hw(par->diwstrt_h, par->diwstrt_v), diwstrt); | ||
2291 | (copl++)->l = CMOVE(diwstop2hw(par->diwstop_h, par->diwstop_v), diwstop); | ||
2292 | if (!IS_OCS) { | ||
2293 | (copl++)->l = CMOVE(diwhigh2hw(par->diwstrt_h, par->diwstrt_v, | ||
2294 | par->diwstop_h, par->diwstop_v), diwhigh); | ||
2295 | #if 0 | ||
2296 | if (par->beamcon0 & BMC0_VARBEAMEN) { | ||
2297 | (copl++)->l = CMOVE(vtotal2hw(par->vtotal), vtotal); | ||
2298 | (copl++)->l = CMOVE(vbstrt2hw(par->vbstrt), vbstrt); | ||
2299 | (copl++)->l = CMOVE(vbstop2hw(par->vbstop), vbstop); | ||
2300 | } | ||
2301 | #endif | ||
2302 | } | ||
2303 | } | ||
2304 | copdisplay.rebuild[1] = copl; | ||
2305 | |||
2306 | ami_update_par(info); | ||
2307 | ami_rebuild_copper(info->par); | ||
2308 | } | ||
1174 | 2309 | ||
1175 | static struct fb_ops amifb_ops = { | ||
1176 | .owner = THIS_MODULE, | ||
1177 | .fb_check_var = amifb_check_var, | ||
1178 | .fb_set_par = amifb_set_par, | ||
1179 | .fb_setcolreg = amifb_setcolreg, | ||
1180 | .fb_blank = amifb_blank, | ||
1181 | .fb_pan_display = amifb_pan_display, | ||
1182 | .fb_fillrect = amifb_fillrect, | ||
1183 | .fb_copyarea = amifb_copyarea, | ||
1184 | .fb_imageblit = amifb_imageblit, | ||
1185 | .fb_ioctl = amifb_ioctl, | ||
1186 | }; | ||
1187 | 2310 | ||
1188 | static void __init amifb_setup_mcap(char *spec) | 2311 | static void __init amifb_setup_mcap(char *spec) |
1189 | { | 2312 | { |
@@ -1216,13 +2339,13 @@ static void __init amifb_setup_mcap(char *spec) | |||
1216 | if (hmax <= 0 || hmax <= hmin) | 2339 | if (hmax <= 0 || hmax <= hmin) |
1217 | return; | 2340 | return; |
1218 | 2341 | ||
1219 | fb_info.monspecs.vfmin = vmin; | 2342 | amifb_hfmin = hmin; |
1220 | fb_info.monspecs.vfmax = vmax; | 2343 | amifb_hfmax = hmax; |
1221 | fb_info.monspecs.hfmin = hmin; | 2344 | amifb_vfmin = vmin; |
1222 | fb_info.monspecs.hfmax = hmax; | 2345 | amifb_vfmax = vmax; |
1223 | } | 2346 | } |
1224 | 2347 | ||
1225 | int __init amifb_setup(char *options) | 2348 | static int __init amifb_setup(char *options) |
1226 | { | 2349 | { |
1227 | char *this_opt; | 2350 | char *this_opt; |
1228 | 2351 | ||
@@ -1238,9 +2361,9 @@ int __init amifb_setup(char *options) | |||
1238 | } else if (!strcmp(this_opt, "ilbm")) | 2361 | } else if (!strcmp(this_opt, "ilbm")) |
1239 | amifb_ilbm = 1; | 2362 | amifb_ilbm = 1; |
1240 | else if (!strncmp(this_opt, "monitorcap:", 11)) | 2363 | else if (!strncmp(this_opt, "monitorcap:", 11)) |
1241 | amifb_setup_mcap(this_opt+11); | 2364 | amifb_setup_mcap(this_opt + 11); |
1242 | else if (!strncmp(this_opt, "fstart:", 7)) | 2365 | else if (!strncmp(this_opt, "fstart:", 7)) |
1243 | min_fstrt = simple_strtoul(this_opt+7, NULL, 0); | 2366 | min_fstrt = simple_strtoul(this_opt + 7, NULL, 0); |
1244 | else | 2367 | else |
1245 | mode_option = this_opt; | 2368 | mode_option = this_opt; |
1246 | } | 2369 | } |
@@ -1259,7 +2382,8 @@ static int amifb_check_var(struct fb_var_screeninfo *var, | |||
1259 | struct amifb_par par; | 2382 | struct amifb_par par; |
1260 | 2383 | ||
1261 | /* Validate wanted screen parameters */ | 2384 | /* Validate wanted screen parameters */ |
1262 | if ((err = ami_decode_var(var, &par))) | 2385 | err = ami_decode_var(var, &par, info); |
2386 | if (err) | ||
1263 | return err; | 2387 | return err; |
1264 | 2388 | ||
1265 | /* Encode (possibly rounded) screen parameters */ | 2389 | /* Encode (possibly rounded) screen parameters */ |
@@ -1270,16 +2394,19 @@ static int amifb_check_var(struct fb_var_screeninfo *var, | |||
1270 | 2394 | ||
1271 | static int amifb_set_par(struct fb_info *info) | 2395 | static int amifb_set_par(struct fb_info *info) |
1272 | { | 2396 | { |
1273 | struct amifb_par *par = (struct amifb_par *)info->par; | 2397 | struct amifb_par *par = info->par; |
2398 | int error; | ||
1274 | 2399 | ||
1275 | do_vmode_pan = 0; | 2400 | do_vmode_pan = 0; |
1276 | do_vmode_full = 0; | 2401 | do_vmode_full = 0; |
1277 | 2402 | ||
1278 | /* Decode wanted screen parameters */ | 2403 | /* Decode wanted screen parameters */ |
1279 | ami_decode_var(&info->var, par); | 2404 | error = ami_decode_var(&info->var, par, info); |
2405 | if (error) | ||
2406 | return error; | ||
1280 | 2407 | ||
1281 | /* Set new videomode */ | 2408 | /* Set new videomode */ |
1282 | ami_build_copper(); | 2409 | ami_build_copper(info); |
1283 | 2410 | ||
1284 | /* Set VBlank trigger */ | 2411 | /* Set VBlank trigger */ |
1285 | do_vmode_full = 1; | 2412 | do_vmode_full = 1; |
@@ -1295,20 +2422,20 @@ static int amifb_set_par(struct fb_info *info) | |||
1295 | info->fix.type = FB_TYPE_PLANES; | 2422 | info->fix.type = FB_TYPE_PLANES; |
1296 | info->fix.type_aux = 0; | 2423 | info->fix.type_aux = 0; |
1297 | } | 2424 | } |
1298 | info->fix.line_length = div8(upx(16<<maxfmode, par->vxres)); | 2425 | info->fix.line_length = div8(upx(16 << maxfmode, par->vxres)); |
1299 | 2426 | ||
1300 | if (par->vmode & FB_VMODE_YWRAP) { | 2427 | if (par->vmode & FB_VMODE_YWRAP) { |
1301 | info->fix.ywrapstep = 1; | 2428 | info->fix.ywrapstep = 1; |
1302 | info->fix.xpanstep = 0; | 2429 | info->fix.xpanstep = 0; |
1303 | info->fix.ypanstep = 0; | 2430 | info->fix.ypanstep = 0; |
1304 | info->flags = FBINFO_DEFAULT | FBINFO_HWACCEL_YWRAP | | 2431 | info->flags = FBINFO_DEFAULT | FBINFO_HWACCEL_YWRAP | |
1305 | FBINFO_READS_FAST; /* override SCROLL_REDRAW */ | 2432 | FBINFO_READS_FAST; /* override SCROLL_REDRAW */ |
1306 | } else { | 2433 | } else { |
1307 | info->fix.ywrapstep = 0; | 2434 | info->fix.ywrapstep = 0; |
1308 | if (par->vmode & FB_VMODE_SMOOTH_XPAN) | 2435 | if (par->vmode & FB_VMODE_SMOOTH_XPAN) |
1309 | info->fix.xpanstep = 1; | 2436 | info->fix.xpanstep = 1; |
1310 | else | 2437 | else |
1311 | info->fix.xpanstep = 16<<maxfmode; | 2438 | info->fix.xpanstep = 16 << maxfmode; |
1312 | info->fix.ypanstep = 1; | 2439 | info->fix.ypanstep = 1; |
1313 | info->flags = FBINFO_DEFAULT | FBINFO_HWACCEL_YPAN; | 2440 | info->flags = FBINFO_DEFAULT | FBINFO_HWACCEL_YPAN; |
1314 | } | 2441 | } |
@@ -1317,6 +2444,95 @@ static int amifb_set_par(struct fb_info *info) | |||
1317 | 2444 | ||
1318 | 2445 | ||
1319 | /* | 2446 | /* |
2447 | * Set a single color register. The values supplied are already | ||
2448 | * rounded down to the hardware's capabilities (according to the | ||
2449 | * entries in the var structure). Return != 0 for invalid regno. | ||
2450 | */ | ||
2451 | |||
2452 | static int amifb_setcolreg(u_int regno, u_int red, u_int green, u_int blue, | ||
2453 | u_int transp, struct fb_info *info) | ||
2454 | { | ||
2455 | const struct amifb_par *par = info->par; | ||
2456 | |||
2457 | if (IS_AGA) { | ||
2458 | if (regno > 255) | ||
2459 | return 1; | ||
2460 | } else if (par->bplcon0 & BPC0_SHRES) { | ||
2461 | if (regno > 3) | ||
2462 | return 1; | ||
2463 | } else { | ||
2464 | if (regno > 31) | ||
2465 | return 1; | ||
2466 | } | ||
2467 | red >>= 8; | ||
2468 | green >>= 8; | ||
2469 | blue >>= 8; | ||
2470 | if (!regno) { | ||
2471 | red0 = red; | ||
2472 | green0 = green; | ||
2473 | blue0 = blue; | ||
2474 | } | ||
2475 | |||
2476 | /* | ||
2477 | * Update the corresponding Hardware Color Register, unless it's Color | ||
2478 | * Register 0 and the screen is blanked. | ||
2479 | * | ||
2480 | * VBlank is switched off to protect bplcon3 or ecs_palette[] from | ||
2481 | * being changed by ami_do_blank() during the VBlank. | ||
2482 | */ | ||
2483 | |||
2484 | if (regno || !is_blanked) { | ||
2485 | #if defined(CONFIG_FB_AMIGA_AGA) | ||
2486 | if (IS_AGA) { | ||
2487 | u_short bplcon3 = par->bplcon3; | ||
2488 | VBlankOff(); | ||
2489 | custom.bplcon3 = bplcon3 | (regno << 8 & 0xe000); | ||
2490 | custom.color[regno & 31] = rgb2hw8_high(red, green, | ||
2491 | blue); | ||
2492 | custom.bplcon3 = bplcon3 | (regno << 8 & 0xe000) | | ||
2493 | BPC3_LOCT; | ||
2494 | custom.color[regno & 31] = rgb2hw8_low(red, green, | ||
2495 | blue); | ||
2496 | custom.bplcon3 = bplcon3; | ||
2497 | VBlankOn(); | ||
2498 | } else | ||
2499 | #endif | ||
2500 | #if defined(CONFIG_FB_AMIGA_ECS) | ||
2501 | if (par->bplcon0 & BPC0_SHRES) { | ||
2502 | u_short color, mask; | ||
2503 | int i; | ||
2504 | |||
2505 | mask = 0x3333; | ||
2506 | color = rgb2hw2(red, green, blue); | ||
2507 | VBlankOff(); | ||
2508 | for (i = regno + 12; i >= (int)regno; i -= 4) | ||
2509 | custom.color[i] = ecs_palette[i] = (ecs_palette[i] & mask) | color; | ||
2510 | mask <<= 2; color >>= 2; | ||
2511 | regno = down16(regno) + mul4(mod4(regno)); | ||
2512 | for (i = regno + 3; i >= (int)regno; i--) | ||
2513 | custom.color[i] = ecs_palette[i] = (ecs_palette[i] & mask) | color; | ||
2514 | VBlankOn(); | ||
2515 | } else | ||
2516 | #endif | ||
2517 | custom.color[regno] = rgb2hw4(red, green, blue); | ||
2518 | } | ||
2519 | return 0; | ||
2520 | } | ||
2521 | |||
2522 | |||
2523 | /* | ||
2524 | * Blank the display. | ||
2525 | */ | ||
2526 | |||
2527 | static int amifb_blank(int blank, struct fb_info *info) | ||
2528 | { | ||
2529 | do_blank = blank ? blank : -1; | ||
2530 | |||
2531 | return 0; | ||
2532 | } | ||
2533 | |||
2534 | |||
2535 | /* | ||
1320 | * Pan or Wrap the Display | 2536 | * Pan or Wrap the Display |
1321 | * | 2537 | * |
1322 | * This call looks only at xoffset, yoffset and the FB_VMODE_YWRAP flag | 2538 | * This call looks only at xoffset, yoffset and the FB_VMODE_YWRAP flag |
@@ -1327,18 +2543,19 @@ static int amifb_pan_display(struct fb_var_screeninfo *var, | |||
1327 | { | 2543 | { |
1328 | if (var->vmode & FB_VMODE_YWRAP) { | 2544 | if (var->vmode & FB_VMODE_YWRAP) { |
1329 | if (var->yoffset < 0 || | 2545 | if (var->yoffset < 0 || |
1330 | var->yoffset >= info->var.yres_virtual || var->xoffset) | 2546 | var->yoffset >= info->var.yres_virtual || var->xoffset) |
1331 | return -EINVAL; | 2547 | return -EINVAL; |
1332 | } else { | 2548 | } else { |
1333 | /* | 2549 | /* |
1334 | * TODO: There will be problems when xpan!=1, so some columns | 2550 | * TODO: There will be problems when xpan!=1, so some columns |
1335 | * on the right side will never be seen | 2551 | * on the right side will never be seen |
1336 | */ | 2552 | */ |
1337 | if (var->xoffset+info->var.xres > upx(16<<maxfmode, info->var.xres_virtual) || | 2553 | if (var->xoffset + info->var.xres > |
1338 | var->yoffset+info->var.yres > info->var.yres_virtual) | 2554 | upx(16 << maxfmode, info->var.xres_virtual) || |
2555 | var->yoffset + info->var.yres > info->var.yres_virtual) | ||
1339 | return -EINVAL; | 2556 | return -EINVAL; |
1340 | } | 2557 | } |
1341 | ami_pan_var(var); | 2558 | ami_pan_var(var, info); |
1342 | info->var.xoffset = var->xoffset; | 2559 | info->var.xoffset = var->xoffset; |
1343 | info->var.yoffset = var->yoffset; | 2560 | info->var.yoffset = var->yoffset; |
1344 | if (var->vmode & FB_VMODE_YWRAP) | 2561 | if (var->vmode & FB_VMODE_YWRAP) |
@@ -1360,10 +2577,10 @@ static int amifb_pan_display(struct fb_var_screeninfo *var, | |||
1360 | #endif | 2577 | #endif |
1361 | 2578 | ||
1362 | 2579 | ||
1363 | /* | 2580 | /* |
1364 | * Compose two values, using a bitmask as decision value | 2581 | * Compose two values, using a bitmask as decision value |
1365 | * This is equivalent to (a & mask) | (b & ~mask) | 2582 | * This is equivalent to (a & mask) | (b & ~mask) |
1366 | */ | 2583 | */ |
1367 | 2584 | ||
1368 | static inline unsigned long comp(unsigned long a, unsigned long b, | 2585 | static inline unsigned long comp(unsigned long a, unsigned long b, |
1369 | unsigned long mask) | 2586 | unsigned long mask) |
@@ -1379,29 +2596,29 @@ static inline unsigned long xor(unsigned long a, unsigned long b, | |||
1379 | } | 2596 | } |
1380 | 2597 | ||
1381 | 2598 | ||
1382 | /* | 2599 | /* |
1383 | * Unaligned forward bit copy using 32-bit or 64-bit memory accesses | 2600 | * Unaligned forward bit copy using 32-bit or 64-bit memory accesses |
1384 | */ | 2601 | */ |
1385 | 2602 | ||
1386 | static void bitcpy(unsigned long *dst, int dst_idx, const unsigned long *src, | 2603 | static void bitcpy(unsigned long *dst, int dst_idx, const unsigned long *src, |
1387 | int src_idx, u32 n) | 2604 | int src_idx, u32 n) |
1388 | { | 2605 | { |
1389 | unsigned long first, last; | 2606 | unsigned long first, last; |
1390 | int shift = dst_idx-src_idx, left, right; | 2607 | int shift = dst_idx - src_idx, left, right; |
1391 | unsigned long d0, d1; | 2608 | unsigned long d0, d1; |
1392 | int m; | 2609 | int m; |
1393 | 2610 | ||
1394 | if (!n) | 2611 | if (!n) |
1395 | return; | 2612 | return; |
1396 | 2613 | ||
1397 | shift = dst_idx-src_idx; | 2614 | shift = dst_idx - src_idx; |
1398 | first = ~0UL >> dst_idx; | 2615 | first = ~0UL >> dst_idx; |
1399 | last = ~(~0UL >> ((dst_idx+n) % BITS_PER_LONG)); | 2616 | last = ~(~0UL >> ((dst_idx + n) % BITS_PER_LONG)); |
1400 | 2617 | ||
1401 | if (!shift) { | 2618 | if (!shift) { |
1402 | // Same alignment for source and dest | 2619 | // Same alignment for source and dest |
1403 | 2620 | ||
1404 | if (dst_idx+n <= BITS_PER_LONG) { | 2621 | if (dst_idx + n <= BITS_PER_LONG) { |
1405 | // Single word | 2622 | // Single word |
1406 | if (last) | 2623 | if (last) |
1407 | first &= last; | 2624 | first &= last; |
@@ -1413,7 +2630,7 @@ static void bitcpy(unsigned long *dst, int dst_idx, const unsigned long *src, | |||
1413 | *dst = comp(*src, *dst, first); | 2630 | *dst = comp(*src, *dst, first); |
1414 | dst++; | 2631 | dst++; |
1415 | src++; | 2632 | src++; |
1416 | n -= BITS_PER_LONG-dst_idx; | 2633 | n -= BITS_PER_LONG - dst_idx; |
1417 | } | 2634 | } |
1418 | 2635 | ||
1419 | // Main chunk | 2636 | // Main chunk |
@@ -1439,17 +2656,17 @@ static void bitcpy(unsigned long *dst, int dst_idx, const unsigned long *src, | |||
1439 | } else { | 2656 | } else { |
1440 | // Different alignment for source and dest | 2657 | // Different alignment for source and dest |
1441 | 2658 | ||
1442 | right = shift & (BITS_PER_LONG-1); | 2659 | right = shift & (BITS_PER_LONG - 1); |
1443 | left = -shift & (BITS_PER_LONG-1); | 2660 | left = -shift & (BITS_PER_LONG - 1); |
1444 | 2661 | ||
1445 | if (dst_idx+n <= BITS_PER_LONG) { | 2662 | if (dst_idx + n <= BITS_PER_LONG) { |
1446 | // Single destination word | 2663 | // Single destination word |
1447 | if (last) | 2664 | if (last) |
1448 | first &= last; | 2665 | first &= last; |
1449 | if (shift > 0) { | 2666 | if (shift > 0) { |
1450 | // Single source word | 2667 | // Single source word |
1451 | *dst = comp(*src >> right, *dst, first); | 2668 | *dst = comp(*src >> right, *dst, first); |
1452 | } else if (src_idx+n <= BITS_PER_LONG) { | 2669 | } else if (src_idx + n <= BITS_PER_LONG) { |
1453 | // Single source word | 2670 | // Single source word |
1454 | *dst = comp(*src << left, *dst, first); | 2671 | *dst = comp(*src << left, *dst, first); |
1455 | } else { | 2672 | } else { |
@@ -1467,7 +2684,7 @@ static void bitcpy(unsigned long *dst, int dst_idx, const unsigned long *src, | |||
1467 | // Single source word | 2684 | // Single source word |
1468 | *dst = comp(d0 >> right, *dst, first); | 2685 | *dst = comp(d0 >> right, *dst, first); |
1469 | dst++; | 2686 | dst++; |
1470 | n -= BITS_PER_LONG-dst_idx; | 2687 | n -= BITS_PER_LONG - dst_idx; |
1471 | } else { | 2688 | } else { |
1472 | // 2 source words | 2689 | // 2 source words |
1473 | d1 = *src++; | 2690 | d1 = *src++; |
@@ -1475,7 +2692,7 @@ static void bitcpy(unsigned long *dst, int dst_idx, const unsigned long *src, | |||
1475 | first); | 2692 | first); |
1476 | d0 = d1; | 2693 | d0 = d1; |
1477 | dst++; | 2694 | dst++; |
1478 | n -= BITS_PER_LONG-dst_idx; | 2695 | n -= BITS_PER_LONG - dst_idx; |
1479 | } | 2696 | } |
1480 | 2697 | ||
1481 | // Main chunk | 2698 | // Main chunk |
@@ -1519,40 +2736,40 @@ static void bitcpy(unsigned long *dst, int dst_idx, const unsigned long *src, | |||
1519 | } | 2736 | } |
1520 | 2737 | ||
1521 | 2738 | ||
1522 | /* | 2739 | /* |
1523 | * Unaligned reverse bit copy using 32-bit or 64-bit memory accesses | 2740 | * Unaligned reverse bit copy using 32-bit or 64-bit memory accesses |
1524 | */ | 2741 | */ |
1525 | 2742 | ||
1526 | static void bitcpy_rev(unsigned long *dst, int dst_idx, | 2743 | static void bitcpy_rev(unsigned long *dst, int dst_idx, |
1527 | const unsigned long *src, int src_idx, u32 n) | 2744 | const unsigned long *src, int src_idx, u32 n) |
1528 | { | 2745 | { |
1529 | unsigned long first, last; | 2746 | unsigned long first, last; |
1530 | int shift = dst_idx-src_idx, left, right; | 2747 | int shift = dst_idx - src_idx, left, right; |
1531 | unsigned long d0, d1; | 2748 | unsigned long d0, d1; |
1532 | int m; | 2749 | int m; |
1533 | 2750 | ||
1534 | if (!n) | 2751 | if (!n) |
1535 | return; | 2752 | return; |
1536 | 2753 | ||
1537 | dst += (n-1)/BITS_PER_LONG; | 2754 | dst += (n - 1) / BITS_PER_LONG; |
1538 | src += (n-1)/BITS_PER_LONG; | 2755 | src += (n - 1) / BITS_PER_LONG; |
1539 | if ((n-1) % BITS_PER_LONG) { | 2756 | if ((n - 1) % BITS_PER_LONG) { |
1540 | dst_idx += (n-1) % BITS_PER_LONG; | 2757 | dst_idx += (n - 1) % BITS_PER_LONG; |
1541 | dst += dst_idx >> SHIFT_PER_LONG; | 2758 | dst += dst_idx >> SHIFT_PER_LONG; |
1542 | dst_idx &= BITS_PER_LONG-1; | 2759 | dst_idx &= BITS_PER_LONG - 1; |
1543 | src_idx += (n-1) % BITS_PER_LONG; | 2760 | src_idx += (n - 1) % BITS_PER_LONG; |
1544 | src += src_idx >> SHIFT_PER_LONG; | 2761 | src += src_idx >> SHIFT_PER_LONG; |
1545 | src_idx &= BITS_PER_LONG-1; | 2762 | src_idx &= BITS_PER_LONG - 1; |
1546 | } | 2763 | } |
1547 | 2764 | ||
1548 | shift = dst_idx-src_idx; | 2765 | shift = dst_idx - src_idx; |
1549 | first = ~0UL << (BITS_PER_LONG-1-dst_idx); | 2766 | first = ~0UL << (BITS_PER_LONG - 1 - dst_idx); |
1550 | last = ~(~0UL << (BITS_PER_LONG-1-((dst_idx-n) % BITS_PER_LONG))); | 2767 | last = ~(~0UL << (BITS_PER_LONG - 1 - ((dst_idx - n) % BITS_PER_LONG))); |
1551 | 2768 | ||
1552 | if (!shift) { | 2769 | if (!shift) { |
1553 | // Same alignment for source and dest | 2770 | // Same alignment for source and dest |
1554 | 2771 | ||
1555 | if ((unsigned long)dst_idx+1 >= n) { | 2772 | if ((unsigned long)dst_idx + 1 >= n) { |
1556 | // Single word | 2773 | // Single word |
1557 | if (last) | 2774 | if (last) |
1558 | first &= last; | 2775 | first &= last; |
@@ -1564,7 +2781,7 @@ static void bitcpy_rev(unsigned long *dst, int dst_idx, | |||
1564 | *dst = comp(*src, *dst, first); | 2781 | *dst = comp(*src, *dst, first); |
1565 | dst--; | 2782 | dst--; |
1566 | src--; | 2783 | src--; |
1567 | n -= dst_idx+1; | 2784 | n -= dst_idx + 1; |
1568 | } | 2785 | } |
1569 | 2786 | ||
1570 | // Main chunk | 2787 | // Main chunk |
@@ -1590,17 +2807,17 @@ static void bitcpy_rev(unsigned long *dst, int dst_idx, | |||
1590 | } else { | 2807 | } else { |
1591 | // Different alignment for source and dest | 2808 | // Different alignment for source and dest |
1592 | 2809 | ||
1593 | right = shift & (BITS_PER_LONG-1); | 2810 | right = shift & (BITS_PER_LONG - 1); |
1594 | left = -shift & (BITS_PER_LONG-1); | 2811 | left = -shift & (BITS_PER_LONG - 1); |
1595 | 2812 | ||
1596 | if ((unsigned long)dst_idx+1 >= n) { | 2813 | if ((unsigned long)dst_idx + 1 >= n) { |
1597 | // Single destination word | 2814 | // Single destination word |
1598 | if (last) | 2815 | if (last) |
1599 | first &= last; | 2816 | first &= last; |
1600 | if (shift < 0) { | 2817 | if (shift < 0) { |
1601 | // Single source word | 2818 | // Single source word |
1602 | *dst = comp(*src << left, *dst, first); | 2819 | *dst = comp(*src << left, *dst, first); |
1603 | } else if (1+(unsigned long)src_idx >= n) { | 2820 | } else if (1 + (unsigned long)src_idx >= n) { |
1604 | // Single source word | 2821 | // Single source word |
1605 | *dst = comp(*src >> right, *dst, first); | 2822 | *dst = comp(*src >> right, *dst, first); |
1606 | } else { | 2823 | } else { |
@@ -1618,7 +2835,7 @@ static void bitcpy_rev(unsigned long *dst, int dst_idx, | |||
1618 | // Single source word | 2835 | // Single source word |
1619 | *dst = comp(d0 << left, *dst, first); | 2836 | *dst = comp(d0 << left, *dst, first); |
1620 | dst--; | 2837 | dst--; |
1621 | n -= dst_idx+1; | 2838 | n -= dst_idx + 1; |
1622 | } else { | 2839 | } else { |
1623 | // 2 source words | 2840 | // 2 source words |
1624 | d1 = *src--; | 2841 | d1 = *src--; |
@@ -1626,7 +2843,7 @@ static void bitcpy_rev(unsigned long *dst, int dst_idx, | |||
1626 | first); | 2843 | first); |
1627 | d0 = d1; | 2844 | d0 = d1; |
1628 | dst--; | 2845 | dst--; |
1629 | n -= dst_idx+1; | 2846 | n -= dst_idx + 1; |
1630 | } | 2847 | } |
1631 | 2848 | ||
1632 | // Main chunk | 2849 | // Main chunk |
@@ -1670,30 +2887,30 @@ static void bitcpy_rev(unsigned long *dst, int dst_idx, | |||
1670 | } | 2887 | } |
1671 | 2888 | ||
1672 | 2889 | ||
1673 | /* | 2890 | /* |
1674 | * Unaligned forward inverting bit copy using 32-bit or 64-bit memory | 2891 | * Unaligned forward inverting bit copy using 32-bit or 64-bit memory |
1675 | * accesses | 2892 | * accesses |
1676 | */ | 2893 | */ |
1677 | 2894 | ||
1678 | static void bitcpy_not(unsigned long *dst, int dst_idx, | 2895 | static void bitcpy_not(unsigned long *dst, int dst_idx, |
1679 | const unsigned long *src, int src_idx, u32 n) | 2896 | const unsigned long *src, int src_idx, u32 n) |
1680 | { | 2897 | { |
1681 | unsigned long first, last; | 2898 | unsigned long first, last; |
1682 | int shift = dst_idx-src_idx, left, right; | 2899 | int shift = dst_idx - src_idx, left, right; |
1683 | unsigned long d0, d1; | 2900 | unsigned long d0, d1; |
1684 | int m; | 2901 | int m; |
1685 | 2902 | ||
1686 | if (!n) | 2903 | if (!n) |
1687 | return; | 2904 | return; |
1688 | 2905 | ||
1689 | shift = dst_idx-src_idx; | 2906 | shift = dst_idx - src_idx; |
1690 | first = ~0UL >> dst_idx; | 2907 | first = ~0UL >> dst_idx; |
1691 | last = ~(~0UL >> ((dst_idx+n) % BITS_PER_LONG)); | 2908 | last = ~(~0UL >> ((dst_idx + n) % BITS_PER_LONG)); |
1692 | 2909 | ||
1693 | if (!shift) { | 2910 | if (!shift) { |
1694 | // Same alignment for source and dest | 2911 | // Same alignment for source and dest |
1695 | 2912 | ||
1696 | if (dst_idx+n <= BITS_PER_LONG) { | 2913 | if (dst_idx + n <= BITS_PER_LONG) { |
1697 | // Single word | 2914 | // Single word |
1698 | if (last) | 2915 | if (last) |
1699 | first &= last; | 2916 | first &= last; |
@@ -1705,7 +2922,7 @@ static void bitcpy_not(unsigned long *dst, int dst_idx, | |||
1705 | *dst = comp(~*src, *dst, first); | 2922 | *dst = comp(~*src, *dst, first); |
1706 | dst++; | 2923 | dst++; |
1707 | src++; | 2924 | src++; |
1708 | n -= BITS_PER_LONG-dst_idx; | 2925 | n -= BITS_PER_LONG - dst_idx; |
1709 | } | 2926 | } |
1710 | 2927 | ||
1711 | // Main chunk | 2928 | // Main chunk |
@@ -1731,17 +2948,17 @@ static void bitcpy_not(unsigned long *dst, int dst_idx, | |||
1731 | } else { | 2948 | } else { |
1732 | // Different alignment for source and dest | 2949 | // Different alignment for source and dest |
1733 | 2950 | ||
1734 | right = shift & (BITS_PER_LONG-1); | 2951 | right = shift & (BITS_PER_LONG - 1); |
1735 | left = -shift & (BITS_PER_LONG-1); | 2952 | left = -shift & (BITS_PER_LONG - 1); |
1736 | 2953 | ||
1737 | if (dst_idx+n <= BITS_PER_LONG) { | 2954 | if (dst_idx + n <= BITS_PER_LONG) { |
1738 | // Single destination word | 2955 | // Single destination word |
1739 | if (last) | 2956 | if (last) |
1740 | first &= last; | 2957 | first &= last; |
1741 | if (shift > 0) { | 2958 | if (shift > 0) { |
1742 | // Single source word | 2959 | // Single source word |
1743 | *dst = comp(~*src >> right, *dst, first); | 2960 | *dst = comp(~*src >> right, *dst, first); |
1744 | } else if (src_idx+n <= BITS_PER_LONG) { | 2961 | } else if (src_idx + n <= BITS_PER_LONG) { |
1745 | // Single source word | 2962 | // Single source word |
1746 | *dst = comp(~*src << left, *dst, first); | 2963 | *dst = comp(~*src << left, *dst, first); |
1747 | } else { | 2964 | } else { |
@@ -1759,7 +2976,7 @@ static void bitcpy_not(unsigned long *dst, int dst_idx, | |||
1759 | // Single source word | 2976 | // Single source word |
1760 | *dst = comp(d0 >> right, *dst, first); | 2977 | *dst = comp(d0 >> right, *dst, first); |
1761 | dst++; | 2978 | dst++; |
1762 | n -= BITS_PER_LONG-dst_idx; | 2979 | n -= BITS_PER_LONG - dst_idx; |
1763 | } else { | 2980 | } else { |
1764 | // 2 source words | 2981 | // 2 source words |
1765 | d1 = ~*src++; | 2982 | d1 = ~*src++; |
@@ -1767,7 +2984,7 @@ static void bitcpy_not(unsigned long *dst, int dst_idx, | |||
1767 | first); | 2984 | first); |
1768 | d0 = d1; | 2985 | d0 = d1; |
1769 | dst++; | 2986 | dst++; |
1770 | n -= BITS_PER_LONG-dst_idx; | 2987 | n -= BITS_PER_LONG - dst_idx; |
1771 | } | 2988 | } |
1772 | 2989 | ||
1773 | // Main chunk | 2990 | // Main chunk |
@@ -1811,9 +3028,9 @@ static void bitcpy_not(unsigned long *dst, int dst_idx, | |||
1811 | } | 3028 | } |
1812 | 3029 | ||
1813 | 3030 | ||
1814 | /* | 3031 | /* |
1815 | * Unaligned 32-bit pattern fill using 32/64-bit memory accesses | 3032 | * Unaligned 32-bit pattern fill using 32/64-bit memory accesses |
1816 | */ | 3033 | */ |
1817 | 3034 | ||
1818 | static void bitfill32(unsigned long *dst, int dst_idx, u32 pat, u32 n) | 3035 | static void bitfill32(unsigned long *dst, int dst_idx, u32 pat, u32 n) |
1819 | { | 3036 | { |
@@ -1828,9 +3045,9 @@ static void bitfill32(unsigned long *dst, int dst_idx, u32 pat, u32 n) | |||
1828 | #endif | 3045 | #endif |
1829 | 3046 | ||
1830 | first = ~0UL >> dst_idx; | 3047 | first = ~0UL >> dst_idx; |
1831 | last = ~(~0UL >> ((dst_idx+n) % BITS_PER_LONG)); | 3048 | last = ~(~0UL >> ((dst_idx + n) % BITS_PER_LONG)); |
1832 | 3049 | ||
1833 | if (dst_idx+n <= BITS_PER_LONG) { | 3050 | if (dst_idx + n <= BITS_PER_LONG) { |
1834 | // Single word | 3051 | // Single word |
1835 | if (last) | 3052 | if (last) |
1836 | first &= last; | 3053 | first &= last; |
@@ -1841,7 +3058,7 @@ static void bitfill32(unsigned long *dst, int dst_idx, u32 pat, u32 n) | |||
1841 | if (first) { | 3058 | if (first) { |
1842 | *dst = comp(val, *dst, first); | 3059 | *dst = comp(val, *dst, first); |
1843 | dst++; | 3060 | dst++; |
1844 | n -= BITS_PER_LONG-dst_idx; | 3061 | n -= BITS_PER_LONG - dst_idx; |
1845 | } | 3062 | } |
1846 | 3063 | ||
1847 | // Main chunk | 3064 | // Main chunk |
@@ -1867,9 +3084,9 @@ static void bitfill32(unsigned long *dst, int dst_idx, u32 pat, u32 n) | |||
1867 | } | 3084 | } |
1868 | 3085 | ||
1869 | 3086 | ||
1870 | /* | 3087 | /* |
1871 | * Unaligned 32-bit pattern xor using 32/64-bit memory accesses | 3088 | * Unaligned 32-bit pattern xor using 32/64-bit memory accesses |
1872 | */ | 3089 | */ |
1873 | 3090 | ||
1874 | static void bitxor32(unsigned long *dst, int dst_idx, u32 pat, u32 n) | 3091 | static void bitxor32(unsigned long *dst, int dst_idx, u32 pat, u32 n) |
1875 | { | 3092 | { |
@@ -1884,9 +3101,9 @@ static void bitxor32(unsigned long *dst, int dst_idx, u32 pat, u32 n) | |||
1884 | #endif | 3101 | #endif |
1885 | 3102 | ||
1886 | first = ~0UL >> dst_idx; | 3103 | first = ~0UL >> dst_idx; |
1887 | last = ~(~0UL >> ((dst_idx+n) % BITS_PER_LONG)); | 3104 | last = ~(~0UL >> ((dst_idx + n) % BITS_PER_LONG)); |
1888 | 3105 | ||
1889 | if (dst_idx+n <= BITS_PER_LONG) { | 3106 | if (dst_idx + n <= BITS_PER_LONG) { |
1890 | // Single word | 3107 | // Single word |
1891 | if (last) | 3108 | if (last) |
1892 | first &= last; | 3109 | first &= last; |
@@ -1897,7 +3114,7 @@ static void bitxor32(unsigned long *dst, int dst_idx, u32 pat, u32 n) | |||
1897 | if (first) { | 3114 | if (first) { |
1898 | *dst = xor(val, *dst, first); | 3115 | *dst = xor(val, *dst, first); |
1899 | dst++; | 3116 | dst++; |
1900 | n -= BITS_PER_LONG-dst_idx; | 3117 | n -= BITS_PER_LONG - dst_idx; |
1901 | } | 3118 | } |
1902 | 3119 | ||
1903 | // Main chunk | 3120 | // Main chunk |
@@ -1924,12 +3141,12 @@ static inline void fill_one_line(int bpp, unsigned long next_plane, | |||
1924 | { | 3141 | { |
1925 | while (1) { | 3142 | while (1) { |
1926 | dst += dst_idx >> SHIFT_PER_LONG; | 3143 | dst += dst_idx >> SHIFT_PER_LONG; |
1927 | dst_idx &= (BITS_PER_LONG-1); | 3144 | dst_idx &= (BITS_PER_LONG - 1); |
1928 | bitfill32(dst, dst_idx, color & 1 ? ~0 : 0, n); | 3145 | bitfill32(dst, dst_idx, color & 1 ? ~0 : 0, n); |
1929 | if (!--bpp) | 3146 | if (!--bpp) |
1930 | break; | 3147 | break; |
1931 | color >>= 1; | 3148 | color >>= 1; |
1932 | dst_idx += next_plane*8; | 3149 | dst_idx += next_plane * 8; |
1933 | } | 3150 | } |
1934 | } | 3151 | } |
1935 | 3152 | ||
@@ -1939,12 +3156,12 @@ static inline void xor_one_line(int bpp, unsigned long next_plane, | |||
1939 | { | 3156 | { |
1940 | while (color) { | 3157 | while (color) { |
1941 | dst += dst_idx >> SHIFT_PER_LONG; | 3158 | dst += dst_idx >> SHIFT_PER_LONG; |
1942 | dst_idx &= (BITS_PER_LONG-1); | 3159 | dst_idx &= (BITS_PER_LONG - 1); |
1943 | bitxor32(dst, dst_idx, color & 1 ? ~0 : 0, n); | 3160 | bitxor32(dst, dst_idx, color & 1 ? ~0 : 0, n); |
1944 | if (!--bpp) | 3161 | if (!--bpp) |
1945 | break; | 3162 | break; |
1946 | color >>= 1; | 3163 | color >>= 1; |
1947 | dst_idx += next_plane*8; | 3164 | dst_idx += next_plane * 8; |
1948 | } | 3165 | } |
1949 | } | 3166 | } |
1950 | 3167 | ||
@@ -1952,7 +3169,7 @@ static inline void xor_one_line(int bpp, unsigned long next_plane, | |||
1952 | static void amifb_fillrect(struct fb_info *info, | 3169 | static void amifb_fillrect(struct fb_info *info, |
1953 | const struct fb_fillrect *rect) | 3170 | const struct fb_fillrect *rect) |
1954 | { | 3171 | { |
1955 | struct amifb_par *par = (struct amifb_par *)info->par; | 3172 | struct amifb_par *par = info->par; |
1956 | int dst_idx, x2, y2; | 3173 | int dst_idx, x2, y2; |
1957 | unsigned long *dst; | 3174 | unsigned long *dst; |
1958 | u32 width, height; | 3175 | u32 width, height; |
@@ -1972,23 +3189,23 @@ static void amifb_fillrect(struct fb_info *info, | |||
1972 | height = y2 - rect->dy; | 3189 | height = y2 - rect->dy; |
1973 | 3190 | ||
1974 | dst = (unsigned long *) | 3191 | dst = (unsigned long *) |
1975 | ((unsigned long)info->screen_base & ~(BYTES_PER_LONG-1)); | 3192 | ((unsigned long)info->screen_base & ~(BYTES_PER_LONG - 1)); |
1976 | dst_idx = ((unsigned long)info->screen_base & (BYTES_PER_LONG-1))*8; | 3193 | dst_idx = ((unsigned long)info->screen_base & (BYTES_PER_LONG - 1)) * 8; |
1977 | dst_idx += rect->dy*par->next_line*8+rect->dx; | 3194 | dst_idx += rect->dy * par->next_line * 8 + rect->dx; |
1978 | while (height--) { | 3195 | while (height--) { |
1979 | switch (rect->rop) { | 3196 | switch (rect->rop) { |
1980 | case ROP_COPY: | 3197 | case ROP_COPY: |
1981 | fill_one_line(info->var.bits_per_pixel, | 3198 | fill_one_line(info->var.bits_per_pixel, |
1982 | par->next_plane, dst, dst_idx, width, | 3199 | par->next_plane, dst, dst_idx, width, |
1983 | rect->color); | 3200 | rect->color); |
1984 | break; | 3201 | break; |
1985 | 3202 | ||
1986 | case ROP_XOR: | 3203 | case ROP_XOR: |
1987 | xor_one_line(info->var.bits_per_pixel, par->next_plane, | 3204 | xor_one_line(info->var.bits_per_pixel, par->next_plane, |
1988 | dst, dst_idx, width, rect->color); | 3205 | dst, dst_idx, width, rect->color); |
1989 | break; | 3206 | break; |
1990 | } | 3207 | } |
1991 | dst_idx += par->next_line*8; | 3208 | dst_idx += par->next_line * 8; |
1992 | } | 3209 | } |
1993 | } | 3210 | } |
1994 | 3211 | ||
@@ -1998,14 +3215,14 @@ static inline void copy_one_line(int bpp, unsigned long next_plane, | |||
1998 | { | 3215 | { |
1999 | while (1) { | 3216 | while (1) { |
2000 | dst += dst_idx >> SHIFT_PER_LONG; | 3217 | dst += dst_idx >> SHIFT_PER_LONG; |
2001 | dst_idx &= (BITS_PER_LONG-1); | 3218 | dst_idx &= (BITS_PER_LONG - 1); |
2002 | src += src_idx >> SHIFT_PER_LONG; | 3219 | src += src_idx >> SHIFT_PER_LONG; |
2003 | src_idx &= (BITS_PER_LONG-1); | 3220 | src_idx &= (BITS_PER_LONG - 1); |
2004 | bitcpy(dst, dst_idx, src, src_idx, n); | 3221 | bitcpy(dst, dst_idx, src, src_idx, n); |
2005 | if (!--bpp) | 3222 | if (!--bpp) |
2006 | break; | 3223 | break; |
2007 | dst_idx += next_plane*8; | 3224 | dst_idx += next_plane * 8; |
2008 | src_idx += next_plane*8; | 3225 | src_idx += next_plane * 8; |
2009 | } | 3226 | } |
2010 | } | 3227 | } |
2011 | 3228 | ||
@@ -2015,14 +3232,14 @@ static inline void copy_one_line_rev(int bpp, unsigned long next_plane, | |||
2015 | { | 3232 | { |
2016 | while (1) { | 3233 | while (1) { |
2017 | dst += dst_idx >> SHIFT_PER_LONG; | 3234 | dst += dst_idx >> SHIFT_PER_LONG; |
2018 | dst_idx &= (BITS_PER_LONG-1); | 3235 | dst_idx &= (BITS_PER_LONG - 1); |
2019 | src += src_idx >> SHIFT_PER_LONG; | 3236 | src += src_idx >> SHIFT_PER_LONG; |
2020 | src_idx &= (BITS_PER_LONG-1); | 3237 | src_idx &= (BITS_PER_LONG - 1); |
2021 | bitcpy_rev(dst, dst_idx, src, src_idx, n); | 3238 | bitcpy_rev(dst, dst_idx, src, src_idx, n); |
2022 | if (!--bpp) | 3239 | if (!--bpp) |
2023 | break; | 3240 | break; |
2024 | dst_idx += next_plane*8; | 3241 | dst_idx += next_plane * 8; |
2025 | src_idx += next_plane*8; | 3242 | src_idx += next_plane * 8; |
2026 | } | 3243 | } |
2027 | } | 3244 | } |
2028 | 3245 | ||
@@ -2030,7 +3247,7 @@ static inline void copy_one_line_rev(int bpp, unsigned long next_plane, | |||
2030 | static void amifb_copyarea(struct fb_info *info, | 3247 | static void amifb_copyarea(struct fb_info *info, |
2031 | const struct fb_copyarea *area) | 3248 | const struct fb_copyarea *area) |
2032 | { | 3249 | { |
2033 | struct amifb_par *par = (struct amifb_par *)info->par; | 3250 | struct amifb_par *par = info->par; |
2034 | int x2, y2; | 3251 | int x2, y2; |
2035 | u32 dx, dy, sx, sy, width, height; | 3252 | u32 dx, dy, sx, sy, width, height; |
2036 | unsigned long *dst, *src; | 3253 | unsigned long *dst, *src; |
@@ -2065,16 +3282,16 @@ static void amifb_copyarea(struct fb_info *info, | |||
2065 | rev_copy = 1; | 3282 | rev_copy = 1; |
2066 | } | 3283 | } |
2067 | dst = (unsigned long *) | 3284 | dst = (unsigned long *) |
2068 | ((unsigned long)info->screen_base & ~(BYTES_PER_LONG-1)); | 3285 | ((unsigned long)info->screen_base & ~(BYTES_PER_LONG - 1)); |
2069 | src = dst; | 3286 | src = dst; |
2070 | dst_idx = ((unsigned long)info->screen_base & (BYTES_PER_LONG-1))*8; | 3287 | dst_idx = ((unsigned long)info->screen_base & (BYTES_PER_LONG - 1)) * 8; |
2071 | src_idx = dst_idx; | 3288 | src_idx = dst_idx; |
2072 | dst_idx += dy*par->next_line*8+dx; | 3289 | dst_idx += dy * par->next_line * 8 + dx; |
2073 | src_idx += sy*par->next_line*8+sx; | 3290 | src_idx += sy * par->next_line * 8 + sx; |
2074 | if (rev_copy) { | 3291 | if (rev_copy) { |
2075 | while (height--) { | 3292 | while (height--) { |
2076 | dst_idx -= par->next_line*8; | 3293 | dst_idx -= par->next_line * 8; |
2077 | src_idx -= par->next_line*8; | 3294 | src_idx -= par->next_line * 8; |
2078 | copy_one_line_rev(info->var.bits_per_pixel, | 3295 | copy_one_line_rev(info->var.bits_per_pixel, |
2079 | par->next_plane, dst, dst_idx, src, | 3296 | par->next_plane, dst, dst_idx, src, |
2080 | src_idx, width); | 3297 | src_idx, width); |
@@ -2084,8 +3301,8 @@ static void amifb_copyarea(struct fb_info *info, | |||
2084 | copy_one_line(info->var.bits_per_pixel, | 3301 | copy_one_line(info->var.bits_per_pixel, |
2085 | par->next_plane, dst, dst_idx, src, | 3302 | par->next_plane, dst, dst_idx, src, |
2086 | src_idx, width); | 3303 | src_idx, width); |
2087 | dst_idx += par->next_line*8; | 3304 | dst_idx += par->next_line * 8; |
2088 | src_idx += par->next_line*8; | 3305 | src_idx += par->next_line * 8; |
2089 | } | 3306 | } |
2090 | } | 3307 | } |
2091 | } | 3308 | } |
@@ -2095,34 +3312,35 @@ static inline void expand_one_line(int bpp, unsigned long next_plane, | |||
2095 | unsigned long *dst, int dst_idx, u32 n, | 3312 | unsigned long *dst, int dst_idx, u32 n, |
2096 | const u8 *data, u32 bgcolor, u32 fgcolor) | 3313 | const u8 *data, u32 bgcolor, u32 fgcolor) |
2097 | { | 3314 | { |
2098 | const unsigned long *src; | 3315 | const unsigned long *src; |
2099 | int src_idx; | 3316 | int src_idx; |
2100 | 3317 | ||
2101 | while (1) { | 3318 | while (1) { |
2102 | dst += dst_idx >> SHIFT_PER_LONG; | 3319 | dst += dst_idx >> SHIFT_PER_LONG; |
2103 | dst_idx &= (BITS_PER_LONG-1); | 3320 | dst_idx &= (BITS_PER_LONG - 1); |
2104 | if ((bgcolor ^ fgcolor) & 1) { | 3321 | if ((bgcolor ^ fgcolor) & 1) { |
2105 | src = (unsigned long *)((unsigned long)data & ~(BYTES_PER_LONG-1)); | 3322 | src = (unsigned long *) |
2106 | src_idx = ((unsigned long)data & (BYTES_PER_LONG-1))*8; | 3323 | ((unsigned long)data & ~(BYTES_PER_LONG - 1)); |
2107 | if (fgcolor & 1) | 3324 | src_idx = ((unsigned long)data & (BYTES_PER_LONG - 1)) * 8; |
2108 | bitcpy(dst, dst_idx, src, src_idx, n); | 3325 | if (fgcolor & 1) |
2109 | else | 3326 | bitcpy(dst, dst_idx, src, src_idx, n); |
2110 | bitcpy_not(dst, dst_idx, src, src_idx, n); | 3327 | else |
2111 | /* set or clear */ | 3328 | bitcpy_not(dst, dst_idx, src, src_idx, n); |
2112 | } else | 3329 | /* set or clear */ |
2113 | bitfill32(dst, dst_idx, fgcolor & 1 ? ~0 : 0, n); | 3330 | } else |
2114 | if (!--bpp) | 3331 | bitfill32(dst, dst_idx, fgcolor & 1 ? ~0 : 0, n); |
2115 | break; | 3332 | if (!--bpp) |
2116 | bgcolor >>= 1; | 3333 | break; |
2117 | fgcolor >>= 1; | 3334 | bgcolor >>= 1; |
2118 | dst_idx += next_plane*8; | 3335 | fgcolor >>= 1; |
2119 | } | 3336 | dst_idx += next_plane * 8; |
3337 | } | ||
2120 | } | 3338 | } |
2121 | 3339 | ||
2122 | 3340 | ||
2123 | static void amifb_imageblit(struct fb_info *info, const struct fb_image *image) | 3341 | static void amifb_imageblit(struct fb_info *info, const struct fb_image *image) |
2124 | { | 3342 | { |
2125 | struct amifb_par *par = (struct amifb_par *)info->par; | 3343 | struct amifb_par *par = info->par; |
2126 | int x2, y2; | 3344 | int x2, y2; |
2127 | unsigned long *dst; | 3345 | unsigned long *dst; |
2128 | int dst_idx; | 3346 | int dst_idx; |
@@ -2145,17 +3363,17 @@ static void amifb_imageblit(struct fb_info *info, const struct fb_image *image) | |||
2145 | 3363 | ||
2146 | if (image->depth == 1) { | 3364 | if (image->depth == 1) { |
2147 | dst = (unsigned long *) | 3365 | dst = (unsigned long *) |
2148 | ((unsigned long)info->screen_base & ~(BYTES_PER_LONG-1)); | 3366 | ((unsigned long)info->screen_base & ~(BYTES_PER_LONG - 1)); |
2149 | dst_idx = ((unsigned long)info->screen_base & (BYTES_PER_LONG-1))*8; | 3367 | dst_idx = ((unsigned long)info->screen_base & (BYTES_PER_LONG - 1)) * 8; |
2150 | dst_idx += dy*par->next_line*8+dx; | 3368 | dst_idx += dy * par->next_line * 8 + dx; |
2151 | src = image->data; | 3369 | src = image->data; |
2152 | pitch = (image->width+7)/8; | 3370 | pitch = (image->width + 7) / 8; |
2153 | while (height--) { | 3371 | while (height--) { |
2154 | expand_one_line(info->var.bits_per_pixel, | 3372 | expand_one_line(info->var.bits_per_pixel, |
2155 | par->next_plane, dst, dst_idx, width, | 3373 | par->next_plane, dst, dst_idx, width, |
2156 | src, image->bg_color, | 3374 | src, image->bg_color, |
2157 | image->fg_color); | 3375 | image->fg_color); |
2158 | dst_idx += par->next_line*8; | 3376 | dst_idx += par->next_line * 8; |
2159 | src += pitch; | 3377 | src += pitch; |
2160 | } | 3378 | } |
2161 | } else { | 3379 | } else { |
@@ -2182,45 +3400,119 @@ static int amifb_ioctl(struct fb_info *info, | |||
2182 | int i; | 3400 | int i; |
2183 | 3401 | ||
2184 | switch (cmd) { | 3402 | switch (cmd) { |
2185 | case FBIOGET_FCURSORINFO: | 3403 | case FBIOGET_FCURSORINFO: |
2186 | i = ami_get_fix_cursorinfo(&crsr.fix); | 3404 | i = ami_get_fix_cursorinfo(&crsr.fix, info->par); |
2187 | if (i) | 3405 | if (i) |
2188 | return i; | 3406 | return i; |
2189 | return copy_to_user(argp, &crsr.fix, | 3407 | return copy_to_user(argp, &crsr.fix, |
2190 | sizeof(crsr.fix)) ? -EFAULT : 0; | 3408 | sizeof(crsr.fix)) ? -EFAULT : 0; |
2191 | 3409 | ||
2192 | case FBIOGET_VCURSORINFO: | 3410 | case FBIOGET_VCURSORINFO: |
2193 | i = ami_get_var_cursorinfo(&crsr.var, | 3411 | i = ami_get_var_cursorinfo(&crsr.var, |
2194 | ((struct fb_var_cursorinfo __user *)arg)->data); | 3412 | ((struct fb_var_cursorinfo __user *)arg)->data, |
2195 | if (i) | 3413 | info->par); |
2196 | return i; | 3414 | if (i) |
2197 | return copy_to_user(argp, &crsr.var, | 3415 | return i; |
2198 | sizeof(crsr.var)) ? -EFAULT : 0; | 3416 | return copy_to_user(argp, &crsr.var, |
2199 | 3417 | sizeof(crsr.var)) ? -EFAULT : 0; | |
2200 | case FBIOPUT_VCURSORINFO: | 3418 | |
2201 | if (copy_from_user(&crsr.var, argp, sizeof(crsr.var))) | 3419 | case FBIOPUT_VCURSORINFO: |
2202 | return -EFAULT; | 3420 | if (copy_from_user(&crsr.var, argp, sizeof(crsr.var))) |
2203 | return ami_set_var_cursorinfo(&crsr.var, | 3421 | return -EFAULT; |
2204 | ((struct fb_var_cursorinfo __user *)arg)->data); | 3422 | return ami_set_var_cursorinfo(&crsr.var, |
2205 | 3423 | ((struct fb_var_cursorinfo __user *)arg)->data, | |
2206 | case FBIOGET_CURSORSTATE: | 3424 | info->par); |
2207 | i = ami_get_cursorstate(&crsr.state); | 3425 | |
2208 | if (i) | 3426 | case FBIOGET_CURSORSTATE: |
2209 | return i; | 3427 | i = ami_get_cursorstate(&crsr.state, info->par); |
2210 | return copy_to_user(argp, &crsr.state, | 3428 | if (i) |
2211 | sizeof(crsr.state)) ? -EFAULT : 0; | 3429 | return i; |
2212 | 3430 | return copy_to_user(argp, &crsr.state, | |
2213 | case FBIOPUT_CURSORSTATE: | 3431 | sizeof(crsr.state)) ? -EFAULT : 0; |
2214 | if (copy_from_user(&crsr.state, argp, | 3432 | |
2215 | sizeof(crsr.state))) | 3433 | case FBIOPUT_CURSORSTATE: |
2216 | return -EFAULT; | 3434 | if (copy_from_user(&crsr.state, argp, sizeof(crsr.state))) |
2217 | return ami_set_cursorstate(&crsr.state); | 3435 | return -EFAULT; |
3436 | return ami_set_cursorstate(&crsr.state, info->par); | ||
2218 | } | 3437 | } |
2219 | return -EINVAL; | 3438 | return -EINVAL; |
2220 | } | 3439 | } |
2221 | 3440 | ||
2222 | 3441 | ||
2223 | /* | 3442 | /* |
3443 | * Flash the cursor (called by VBlank interrupt) | ||
3444 | */ | ||
3445 | |||
3446 | static int flash_cursor(void) | ||
3447 | { | ||
3448 | static int cursorcount = 1; | ||
3449 | |||
3450 | if (cursormode == FB_CURSOR_FLASH) { | ||
3451 | if (!--cursorcount) { | ||
3452 | cursorstate = -cursorstate; | ||
3453 | cursorcount = cursorrate; | ||
3454 | if (!is_blanked) | ||
3455 | return 1; | ||
3456 | } | ||
3457 | } | ||
3458 | return 0; | ||
3459 | } | ||
3460 | |||
3461 | /* | ||
3462 | * VBlank Display Interrupt | ||
3463 | */ | ||
3464 | |||
3465 | static irqreturn_t amifb_interrupt(int irq, void *dev_id) | ||
3466 | { | ||
3467 | struct amifb_par *par = dev_id; | ||
3468 | |||
3469 | if (do_vmode_pan || do_vmode_full) | ||
3470 | ami_update_display(par); | ||
3471 | |||
3472 | if (do_vmode_full) | ||
3473 | ami_init_display(par); | ||
3474 | |||
3475 | if (do_vmode_pan) { | ||
3476 | flash_cursor(); | ||
3477 | ami_rebuild_copper(par); | ||
3478 | do_cursor = do_vmode_pan = 0; | ||
3479 | } else if (do_cursor) { | ||
3480 | flash_cursor(); | ||
3481 | ami_set_sprite(par); | ||
3482 | do_cursor = 0; | ||
3483 | } else { | ||
3484 | if (flash_cursor()) | ||
3485 | ami_set_sprite(par); | ||
3486 | } | ||
3487 | |||
3488 | if (do_blank) { | ||
3489 | ami_do_blank(par); | ||
3490 | do_blank = 0; | ||
3491 | } | ||
3492 | |||
3493 | if (do_vmode_full) { | ||
3494 | ami_reinit_copper(par); | ||
3495 | do_vmode_full = 0; | ||
3496 | } | ||
3497 | return IRQ_HANDLED; | ||
3498 | } | ||
3499 | |||
3500 | |||
3501 | static struct fb_ops amifb_ops = { | ||
3502 | .owner = THIS_MODULE, | ||
3503 | .fb_check_var = amifb_check_var, | ||
3504 | .fb_set_par = amifb_set_par, | ||
3505 | .fb_setcolreg = amifb_setcolreg, | ||
3506 | .fb_blank = amifb_blank, | ||
3507 | .fb_pan_display = amifb_pan_display, | ||
3508 | .fb_fillrect = amifb_fillrect, | ||
3509 | .fb_copyarea = amifb_copyarea, | ||
3510 | .fb_imageblit = amifb_imageblit, | ||
3511 | .fb_ioctl = amifb_ioctl, | ||
3512 | }; | ||
3513 | |||
3514 | |||
3515 | /* | ||
2224 | * Allocate, Clear and Align a Block of Chip Memory | 3516 | * Allocate, Clear and Align a Block of Chip Memory |
2225 | */ | 3517 | */ |
2226 | 3518 | ||
@@ -2250,6 +3542,7 @@ static inline void chipfree(void) | |||
2250 | 3542 | ||
2251 | static int __init amifb_probe(struct platform_device *pdev) | 3543 | static int __init amifb_probe(struct platform_device *pdev) |
2252 | { | 3544 | { |
3545 | struct fb_info *info; | ||
2253 | int tag, i, err = 0; | 3546 | int tag, i, err = 0; |
2254 | u_long chipptr; | 3547 | u_long chipptr; |
2255 | u_int defmode; | 3548 | u_int defmode; |
@@ -2265,71 +3558,80 @@ static int __init amifb_probe(struct platform_device *pdev) | |||
2265 | #endif | 3558 | #endif |
2266 | custom.dmacon = DMAF_ALL | DMAF_MASTER; | 3559 | custom.dmacon = DMAF_ALL | DMAF_MASTER; |
2267 | 3560 | ||
3561 | info = framebuffer_alloc(sizeof(struct amifb_par), &pdev->dev); | ||
3562 | if (!info) { | ||
3563 | dev_err(&pdev->dev, "framebuffer_alloc failed\n"); | ||
3564 | return -ENOMEM; | ||
3565 | } | ||
3566 | |||
3567 | strcpy(info->fix.id, "Amiga "); | ||
3568 | info->fix.visual = FB_VISUAL_PSEUDOCOLOR; | ||
3569 | info->fix.accel = FB_ACCEL_AMIGABLITT; | ||
3570 | |||
2268 | switch (amiga_chipset) { | 3571 | switch (amiga_chipset) { |
2269 | #ifdef CONFIG_FB_AMIGA_OCS | 3572 | #ifdef CONFIG_FB_AMIGA_OCS |
2270 | case CS_OCS: | 3573 | case CS_OCS: |
2271 | strcat(fb_info.fix.id, "OCS"); | 3574 | strcat(info->fix.id, "OCS"); |
2272 | default_chipset: | 3575 | default_chipset: |
2273 | chipset = TAG_OCS; | 3576 | chipset = TAG_OCS; |
2274 | maxdepth[TAG_SHRES] = 0; /* OCS means no SHRES */ | 3577 | maxdepth[TAG_SHRES] = 0; /* OCS means no SHRES */ |
2275 | maxdepth[TAG_HIRES] = 4; | 3578 | maxdepth[TAG_HIRES] = 4; |
2276 | maxdepth[TAG_LORES] = 6; | 3579 | maxdepth[TAG_LORES] = 6; |
2277 | maxfmode = TAG_FMODE_1; | 3580 | maxfmode = TAG_FMODE_1; |
2278 | defmode = amiga_vblank == 50 ? DEFMODE_PAL | 3581 | defmode = amiga_vblank == 50 ? DEFMODE_PAL : DEFMODE_NTSC; |
2279 | : DEFMODE_NTSC; | 3582 | info->fix.smem_len = VIDEOMEMSIZE_OCS; |
2280 | fb_info.fix.smem_len = VIDEOMEMSIZE_OCS; | 3583 | break; |
2281 | break; | ||
2282 | #endif /* CONFIG_FB_AMIGA_OCS */ | 3584 | #endif /* CONFIG_FB_AMIGA_OCS */ |
2283 | 3585 | ||
2284 | #ifdef CONFIG_FB_AMIGA_ECS | 3586 | #ifdef CONFIG_FB_AMIGA_ECS |
2285 | case CS_ECS: | 3587 | case CS_ECS: |
2286 | strcat(fb_info.fix.id, "ECS"); | 3588 | strcat(info->fix.id, "ECS"); |
2287 | chipset = TAG_ECS; | 3589 | chipset = TAG_ECS; |
2288 | maxdepth[TAG_SHRES] = 2; | 3590 | maxdepth[TAG_SHRES] = 2; |
2289 | maxdepth[TAG_HIRES] = 4; | 3591 | maxdepth[TAG_HIRES] = 4; |
2290 | maxdepth[TAG_LORES] = 6; | 3592 | maxdepth[TAG_LORES] = 6; |
2291 | maxfmode = TAG_FMODE_1; | 3593 | maxfmode = TAG_FMODE_1; |
2292 | if (AMIGAHW_PRESENT(AMBER_FF)) | 3594 | if (AMIGAHW_PRESENT(AMBER_FF)) |
2293 | defmode = amiga_vblank == 50 ? DEFMODE_AMBER_PAL | 3595 | defmode = amiga_vblank == 50 ? DEFMODE_AMBER_PAL |
2294 | : DEFMODE_AMBER_NTSC; | 3596 | : DEFMODE_AMBER_NTSC; |
2295 | else | 3597 | else |
2296 | defmode = amiga_vblank == 50 ? DEFMODE_PAL | 3598 | defmode = amiga_vblank == 50 ? DEFMODE_PAL |
2297 | : DEFMODE_NTSC; | 3599 | : DEFMODE_NTSC; |
2298 | if (amiga_chip_avail()-CHIPRAM_SAFETY_LIMIT > | 3600 | if (amiga_chip_avail() - CHIPRAM_SAFETY_LIMIT > |
2299 | VIDEOMEMSIZE_ECS_2M) | 3601 | VIDEOMEMSIZE_ECS_2M) |
2300 | fb_info.fix.smem_len = VIDEOMEMSIZE_ECS_2M; | 3602 | info->fix.smem_len = VIDEOMEMSIZE_ECS_2M; |
2301 | else | 3603 | else |
2302 | fb_info.fix.smem_len = VIDEOMEMSIZE_ECS_1M; | 3604 | info->fix.smem_len = VIDEOMEMSIZE_ECS_1M; |
2303 | break; | 3605 | break; |
2304 | #endif /* CONFIG_FB_AMIGA_ECS */ | 3606 | #endif /* CONFIG_FB_AMIGA_ECS */ |
2305 | 3607 | ||
2306 | #ifdef CONFIG_FB_AMIGA_AGA | 3608 | #ifdef CONFIG_FB_AMIGA_AGA |
2307 | case CS_AGA: | 3609 | case CS_AGA: |
2308 | strcat(fb_info.fix.id, "AGA"); | 3610 | strcat(info->fix.id, "AGA"); |
2309 | chipset = TAG_AGA; | 3611 | chipset = TAG_AGA; |
2310 | maxdepth[TAG_SHRES] = 8; | 3612 | maxdepth[TAG_SHRES] = 8; |
2311 | maxdepth[TAG_HIRES] = 8; | 3613 | maxdepth[TAG_HIRES] = 8; |
2312 | maxdepth[TAG_LORES] = 8; | 3614 | maxdepth[TAG_LORES] = 8; |
2313 | maxfmode = TAG_FMODE_4; | 3615 | maxfmode = TAG_FMODE_4; |
2314 | defmode = DEFMODE_AGA; | 3616 | defmode = DEFMODE_AGA; |
2315 | if (amiga_chip_avail()-CHIPRAM_SAFETY_LIMIT > | 3617 | if (amiga_chip_avail() - CHIPRAM_SAFETY_LIMIT > |
2316 | VIDEOMEMSIZE_AGA_2M) | 3618 | VIDEOMEMSIZE_AGA_2M) |
2317 | fb_info.fix.smem_len = VIDEOMEMSIZE_AGA_2M; | 3619 | info->fix.smem_len = VIDEOMEMSIZE_AGA_2M; |
2318 | else | 3620 | else |
2319 | fb_info.fix.smem_len = VIDEOMEMSIZE_AGA_1M; | 3621 | info->fix.smem_len = VIDEOMEMSIZE_AGA_1M; |
2320 | break; | 3622 | break; |
2321 | #endif /* CONFIG_FB_AMIGA_AGA */ | 3623 | #endif /* CONFIG_FB_AMIGA_AGA */ |
2322 | 3624 | ||
2323 | default: | 3625 | default: |
2324 | #ifdef CONFIG_FB_AMIGA_OCS | 3626 | #ifdef CONFIG_FB_AMIGA_OCS |
2325 | printk("Unknown graphics chipset, defaulting to OCS\n"); | 3627 | printk("Unknown graphics chipset, defaulting to OCS\n"); |
2326 | strcat(fb_info.fix.id, "Unknown"); | 3628 | strcat(info->fix.id, "Unknown"); |
2327 | goto default_chipset; | 3629 | goto default_chipset; |
2328 | #else /* CONFIG_FB_AMIGA_OCS */ | 3630 | #else /* CONFIG_FB_AMIGA_OCS */ |
2329 | err = -ENODEV; | 3631 | err = -ENODEV; |
2330 | goto amifb_error; | 3632 | goto release; |
2331 | #endif /* CONFIG_FB_AMIGA_OCS */ | 3633 | #endif /* CONFIG_FB_AMIGA_OCS */ |
2332 | break; | 3634 | break; |
2333 | } | 3635 | } |
2334 | 3636 | ||
2335 | /* | 3637 | /* |
@@ -2356,42 +3658,44 @@ default_chipset: | |||
2356 | } | 3658 | } |
2357 | } | 3659 | } |
2358 | 3660 | ||
2359 | /* | 3661 | if (amifb_hfmin) { |
2360 | * These monitor specs are for a typical Amiga monitor (e.g. A1960) | 3662 | info->monspecs.hfmin = amifb_hfmin; |
2361 | */ | 3663 | info->monspecs.hfmax = amifb_hfmax; |
2362 | if (fb_info.monspecs.hfmin == 0) { | 3664 | info->monspecs.vfmin = amifb_vfmin; |
2363 | fb_info.monspecs.hfmin = 15000; | 3665 | info->monspecs.vfmax = amifb_vfmax; |
2364 | fb_info.monspecs.hfmax = 38000; | 3666 | } else { |
2365 | fb_info.monspecs.vfmin = 49; | 3667 | /* |
2366 | fb_info.monspecs.vfmax = 90; | 3668 | * These are for a typical Amiga monitor (e.g. A1960) |
3669 | */ | ||
3670 | info->monspecs.hfmin = 15000; | ||
3671 | info->monspecs.hfmax = 38000; | ||
3672 | info->monspecs.vfmin = 49; | ||
3673 | info->monspecs.vfmax = 90; | ||
2367 | } | 3674 | } |
2368 | 3675 | ||
2369 | fb_info.fbops = &amifb_ops; | 3676 | info->fbops = &amifb_ops; |
2370 | fb_info.par = ¤tpar; | 3677 | info->flags = FBINFO_DEFAULT; |
2371 | fb_info.flags = FBINFO_DEFAULT; | 3678 | info->device = &pdev->dev; |
2372 | fb_info.device = &pdev->dev; | ||
2373 | 3679 | ||
2374 | if (!fb_find_mode(&fb_info.var, &fb_info, mode_option, ami_modedb, | 3680 | if (!fb_find_mode(&info->var, info, mode_option, ami_modedb, |
2375 | NUM_TOTAL_MODES, &ami_modedb[defmode], 4)) { | 3681 | NUM_TOTAL_MODES, &ami_modedb[defmode], 4)) { |
2376 | err = -EINVAL; | 3682 | err = -EINVAL; |
2377 | goto amifb_error; | 3683 | goto release; |
2378 | } | 3684 | } |
2379 | 3685 | ||
2380 | fb_videomode_to_modelist(ami_modedb, NUM_TOTAL_MODES, | 3686 | fb_videomode_to_modelist(ami_modedb, NUM_TOTAL_MODES, |
2381 | &fb_info.modelist); | 3687 | &info->modelist); |
2382 | 3688 | ||
2383 | round_down_bpp = 0; | 3689 | round_down_bpp = 0; |
2384 | chipptr = chipalloc(fb_info.fix.smem_len+ | 3690 | chipptr = chipalloc(info->fix.smem_len + SPRITEMEMSIZE + |
2385 | SPRITEMEMSIZE+ | 3691 | DUMMYSPRITEMEMSIZE + COPINITSIZE + |
2386 | DUMMYSPRITEMEMSIZE+ | 3692 | 4 * COPLISTSIZE); |
2387 | COPINITSIZE+ | ||
2388 | 4*COPLISTSIZE); | ||
2389 | if (!chipptr) { | 3693 | if (!chipptr) { |
2390 | err = -ENOMEM; | 3694 | err = -ENOMEM; |
2391 | goto amifb_error; | 3695 | goto release; |
2392 | } | 3696 | } |
2393 | 3697 | ||
2394 | assignchunk(videomemory, u_long, chipptr, fb_info.fix.smem_len); | 3698 | assignchunk(videomemory, u_long, chipptr, info->fix.smem_len); |
2395 | assignchunk(spritememory, u_long, chipptr, SPRITEMEMSIZE); | 3699 | assignchunk(spritememory, u_long, chipptr, SPRITEMEMSIZE); |
2396 | assignchunk(dummysprite, u_short *, chipptr, DUMMYSPRITEMEMSIZE); | 3700 | assignchunk(dummysprite, u_short *, chipptr, DUMMYSPRITEMEMSIZE); |
2397 | assignchunk(copdisplay.init, copins *, chipptr, COPINITSIZE); | 3701 | assignchunk(copdisplay.init, copins *, chipptr, COPINITSIZE); |
@@ -2403,1398 +3707,78 @@ default_chipset: | |||
2403 | /* | 3707 | /* |
2404 | * access the videomem with writethrough cache | 3708 | * access the videomem with writethrough cache |
2405 | */ | 3709 | */ |
2406 | fb_info.fix.smem_start = (u_long)ZTWO_PADDR(videomemory); | 3710 | info->fix.smem_start = (u_long)ZTWO_PADDR(videomemory); |
2407 | videomemory = (u_long)ioremap_writethrough(fb_info.fix.smem_start, | 3711 | videomemory = (u_long)ioremap_writethrough(info->fix.smem_start, |
2408 | fb_info.fix.smem_len); | 3712 | info->fix.smem_len); |
2409 | if (!videomemory) { | 3713 | if (!videomemory) { |
2410 | printk("amifb: WARNING! unable to map videomem cached writethrough\n"); | 3714 | dev_warn(&pdev->dev, |
2411 | fb_info.screen_base = (char *)ZTWO_VADDR(fb_info.fix.smem_start); | 3715 | "Unable to map videomem cached writethrough\n"); |
3716 | info->screen_base = (char *)ZTWO_VADDR(info->fix.smem_start); | ||
2412 | } else | 3717 | } else |
2413 | fb_info.screen_base = (char *)videomemory; | 3718 | info->screen_base = (char *)videomemory; |
2414 | 3719 | ||
2415 | memset(dummysprite, 0, DUMMYSPRITEMEMSIZE); | 3720 | memset(dummysprite, 0, DUMMYSPRITEMEMSIZE); |
2416 | 3721 | ||
2417 | /* | 3722 | /* |
2418 | * Enable Display DMA | ||
2419 | */ | ||
2420 | |||
2421 | custom.dmacon = DMAF_SETCLR | DMAF_MASTER | DMAF_RASTER | DMAF_COPPER | | ||
2422 | DMAF_BLITTER | DMAF_SPRITE; | ||
2423 | |||
2424 | /* | ||
2425 | * Make sure the Copper has something to do | 3723 | * Make sure the Copper has something to do |
2426 | */ | 3724 | */ |
2427 | |||
2428 | ami_init_copper(); | 3725 | ami_init_copper(); |
2429 | 3726 | ||
2430 | if (request_irq(IRQ_AMIGA_COPPER, amifb_interrupt, 0, | ||
2431 | "fb vertb handler", ¤tpar)) { | ||
2432 | err = -EBUSY; | ||
2433 | goto amifb_error; | ||
2434 | } | ||
2435 | |||
2436 | err = fb_alloc_cmap(&fb_info.cmap, 1<<fb_info.var.bits_per_pixel, 0); | ||
2437 | if (err) | ||
2438 | goto amifb_error; | ||
2439 | |||
2440 | if (register_framebuffer(&fb_info) < 0) { | ||
2441 | err = -EINVAL; | ||
2442 | goto amifb_error; | ||
2443 | } | ||
2444 | |||
2445 | printk("fb%d: %s frame buffer device, using %dK of video memory\n", | ||
2446 | fb_info.node, fb_info.fix.id, fb_info.fix.smem_len>>10); | ||
2447 | |||
2448 | return 0; | ||
2449 | |||
2450 | amifb_error: | ||
2451 | amifb_deinit(pdev); | ||
2452 | return err; | ||
2453 | } | ||
2454 | |||
2455 | static void amifb_deinit(struct platform_device *pdev) | ||
2456 | { | ||
2457 | if (fb_info.cmap.len) | ||
2458 | fb_dealloc_cmap(&fb_info.cmap); | ||
2459 | fb_dealloc_cmap(&fb_info.cmap); | ||
2460 | chipfree(); | ||
2461 | if (videomemory) | ||
2462 | iounmap((void*)videomemory); | ||
2463 | custom.dmacon = DMAF_ALL | DMAF_MASTER; | ||
2464 | } | ||
2465 | |||
2466 | |||
2467 | /* | ||
2468 | * Blank the display. | ||
2469 | */ | ||
2470 | |||
2471 | static int amifb_blank(int blank, struct fb_info *info) | ||
2472 | { | ||
2473 | do_blank = blank ? blank : -1; | ||
2474 | |||
2475 | return 0; | ||
2476 | } | ||
2477 | |||
2478 | /* | ||
2479 | * Flash the cursor (called by VBlank interrupt) | ||
2480 | */ | ||
2481 | |||
2482 | static int flash_cursor(void) | ||
2483 | { | ||
2484 | static int cursorcount = 1; | ||
2485 | |||
2486 | if (cursormode == FB_CURSOR_FLASH) { | ||
2487 | if (!--cursorcount) { | ||
2488 | cursorstate = -cursorstate; | ||
2489 | cursorcount = cursorrate; | ||
2490 | if (!is_blanked) | ||
2491 | return 1; | ||
2492 | } | ||
2493 | } | ||
2494 | return 0; | ||
2495 | } | ||
2496 | |||
2497 | /* | ||
2498 | * VBlank Display Interrupt | ||
2499 | */ | ||
2500 | |||
2501 | static irqreturn_t amifb_interrupt(int irq, void *dev_id) | ||
2502 | { | ||
2503 | if (do_vmode_pan || do_vmode_full) | ||
2504 | ami_update_display(); | ||
2505 | |||
2506 | if (do_vmode_full) | ||
2507 | ami_init_display(); | ||
2508 | |||
2509 | if (do_vmode_pan) { | ||
2510 | flash_cursor(); | ||
2511 | ami_rebuild_copper(); | ||
2512 | do_cursor = do_vmode_pan = 0; | ||
2513 | } else if (do_cursor) { | ||
2514 | flash_cursor(); | ||
2515 | ami_set_sprite(); | ||
2516 | do_cursor = 0; | ||
2517 | } else { | ||
2518 | if (flash_cursor()) | ||
2519 | ami_set_sprite(); | ||
2520 | } | ||
2521 | |||
2522 | if (do_blank) { | ||
2523 | ami_do_blank(); | ||
2524 | do_blank = 0; | ||
2525 | } | ||
2526 | |||
2527 | if (do_vmode_full) { | ||
2528 | ami_reinit_copper(); | ||
2529 | do_vmode_full = 0; | ||
2530 | } | ||
2531 | return IRQ_HANDLED; | ||
2532 | } | ||
2533 | |||
2534 | /* --------------------------- Hardware routines --------------------------- */ | ||
2535 | |||
2536 | /* | ||
2537 | * Get the video params out of `var'. If a value doesn't fit, round | ||
2538 | * it up, if it's too big, return -EINVAL. | ||
2539 | */ | ||
2540 | |||
2541 | static int ami_decode_var(struct fb_var_screeninfo *var, | ||
2542 | struct amifb_par *par) | ||
2543 | { | ||
2544 | u_short clk_shift, line_shift; | ||
2545 | u_long maxfetchstop, fstrt, fsize, fconst, xres_n, yres_n; | ||
2546 | u_int htotal, vtotal; | ||
2547 | |||
2548 | /* | ||
2549 | * Find a matching Pixel Clock | ||
2550 | */ | ||
2551 | |||
2552 | for (clk_shift = TAG_SHRES; clk_shift <= TAG_LORES; clk_shift++) | ||
2553 | if (var->pixclock <= pixclock[clk_shift]) | ||
2554 | break; | ||
2555 | if (clk_shift > TAG_LORES) { | ||
2556 | DPRINTK("pixclock too high\n"); | ||
2557 | return -EINVAL; | ||
2558 | } | ||
2559 | par->clk_shift = clk_shift; | ||
2560 | |||
2561 | /* | ||
2562 | * Check the Geometry Values | ||
2563 | */ | ||
2564 | |||
2565 | if ((par->xres = var->xres) < 64) | ||
2566 | par->xres = 64; | ||
2567 | if ((par->yres = var->yres) < 64) | ||
2568 | par->yres = 64; | ||
2569 | if ((par->vxres = var->xres_virtual) < par->xres) | ||
2570 | par->vxres = par->xres; | ||
2571 | if ((par->vyres = var->yres_virtual) < par->yres) | ||
2572 | par->vyres = par->yres; | ||
2573 | |||
2574 | par->bpp = var->bits_per_pixel; | ||
2575 | if (!var->nonstd) { | ||
2576 | if (par->bpp < 1) | ||
2577 | par->bpp = 1; | ||
2578 | if (par->bpp > maxdepth[clk_shift]) { | ||
2579 | if (round_down_bpp && maxdepth[clk_shift]) | ||
2580 | par->bpp = maxdepth[clk_shift]; | ||
2581 | else { | ||
2582 | DPRINTK("invalid bpp\n"); | ||
2583 | return -EINVAL; | ||
2584 | } | ||
2585 | } | ||
2586 | } else if (var->nonstd == FB_NONSTD_HAM) { | ||
2587 | if (par->bpp < 6) | ||
2588 | par->bpp = 6; | ||
2589 | if (par->bpp != 6) { | ||
2590 | if (par->bpp < 8) | ||
2591 | par->bpp = 8; | ||
2592 | if (par->bpp != 8 || !IS_AGA) { | ||
2593 | DPRINTK("invalid bpp for ham mode\n"); | ||
2594 | return -EINVAL; | ||
2595 | } | ||
2596 | } | ||
2597 | } else { | ||
2598 | DPRINTK("unknown nonstd mode\n"); | ||
2599 | return -EINVAL; | ||
2600 | } | ||
2601 | |||
2602 | /* | ||
2603 | * FB_VMODE_SMOOTH_XPAN will be cleared, if one of the folloing | ||
2604 | * checks failed and smooth scrolling is not possible | ||
2605 | */ | ||
2606 | |||
2607 | par->vmode = var->vmode | FB_VMODE_SMOOTH_XPAN; | ||
2608 | switch (par->vmode & FB_VMODE_MASK) { | ||
2609 | case FB_VMODE_INTERLACED: | ||
2610 | line_shift = 0; | ||
2611 | break; | ||
2612 | case FB_VMODE_NONINTERLACED: | ||
2613 | line_shift = 1; | ||
2614 | break; | ||
2615 | case FB_VMODE_DOUBLE: | ||
2616 | if (!IS_AGA) { | ||
2617 | DPRINTK("double mode only possible with aga\n"); | ||
2618 | return -EINVAL; | ||
2619 | } | ||
2620 | line_shift = 2; | ||
2621 | break; | ||
2622 | default: | ||
2623 | DPRINTK("unknown video mode\n"); | ||
2624 | return -EINVAL; | ||
2625 | break; | ||
2626 | } | ||
2627 | par->line_shift = line_shift; | ||
2628 | |||
2629 | /* | ||
2630 | * Vertical and Horizontal Timings | ||
2631 | */ | ||
2632 | |||
2633 | xres_n = par->xres<<clk_shift; | ||
2634 | yres_n = par->yres<<line_shift; | ||
2635 | par->htotal = down8((var->left_margin+par->xres+var->right_margin+var->hsync_len)<<clk_shift); | ||
2636 | par->vtotal = down2(((var->upper_margin+par->yres+var->lower_margin+var->vsync_len)<<line_shift)+1); | ||
2637 | |||
2638 | if (IS_AGA) | ||
2639 | par->bplcon3 = sprpixmode[clk_shift]; | ||
2640 | else | ||
2641 | par->bplcon3 = 0; | ||
2642 | if (var->sync & FB_SYNC_BROADCAST) { | ||
2643 | par->diwstop_h = par->htotal-((var->right_margin-var->hsync_len)<<clk_shift); | ||
2644 | if (IS_AGA) | ||
2645 | par->diwstop_h += mod4(var->hsync_len); | ||
2646 | else | ||
2647 | par->diwstop_h = down4(par->diwstop_h); | ||
2648 | |||
2649 | par->diwstrt_h = par->diwstop_h - xres_n; | ||
2650 | par->diwstop_v = par->vtotal-((var->lower_margin-var->vsync_len)<<line_shift); | ||
2651 | par->diwstrt_v = par->diwstop_v - yres_n; | ||
2652 | if (par->diwstop_h >= par->htotal+8) { | ||
2653 | DPRINTK("invalid diwstop_h\n"); | ||
2654 | return -EINVAL; | ||
2655 | } | ||
2656 | if (par->diwstop_v > par->vtotal) { | ||
2657 | DPRINTK("invalid diwstop_v\n"); | ||
2658 | return -EINVAL; | ||
2659 | } | ||
2660 | |||
2661 | if (!IS_OCS) { | ||
2662 | /* Initialize sync with some reasonable values for pwrsave */ | ||
2663 | par->hsstrt = 160; | ||
2664 | par->hsstop = 320; | ||
2665 | par->vsstrt = 30; | ||
2666 | par->vsstop = 34; | ||
2667 | } else { | ||
2668 | par->hsstrt = 0; | ||
2669 | par->hsstop = 0; | ||
2670 | par->vsstrt = 0; | ||
2671 | par->vsstop = 0; | ||
2672 | } | ||
2673 | if (par->vtotal > (PAL_VTOTAL+NTSC_VTOTAL)/2) { | ||
2674 | /* PAL video mode */ | ||
2675 | if (par->htotal != PAL_HTOTAL) { | ||
2676 | DPRINTK("htotal invalid for pal\n"); | ||
2677 | return -EINVAL; | ||
2678 | } | ||
2679 | if (par->diwstrt_h < PAL_DIWSTRT_H) { | ||
2680 | DPRINTK("diwstrt_h too low for pal\n"); | ||
2681 | return -EINVAL; | ||
2682 | } | ||
2683 | if (par->diwstrt_v < PAL_DIWSTRT_V) { | ||
2684 | DPRINTK("diwstrt_v too low for pal\n"); | ||
2685 | return -EINVAL; | ||
2686 | } | ||
2687 | htotal = PAL_HTOTAL>>clk_shift; | ||
2688 | vtotal = PAL_VTOTAL>>1; | ||
2689 | if (!IS_OCS) { | ||
2690 | par->beamcon0 = BMC0_PAL; | ||
2691 | par->bplcon3 |= BPC3_BRDRBLNK; | ||
2692 | } else if (AMIGAHW_PRESENT(AGNUS_HR_PAL) || | ||
2693 | AMIGAHW_PRESENT(AGNUS_HR_NTSC)) { | ||
2694 | par->beamcon0 = BMC0_PAL; | ||
2695 | par->hsstop = 1; | ||
2696 | } else if (amiga_vblank != 50) { | ||
2697 | DPRINTK("pal not supported by this chipset\n"); | ||
2698 | return -EINVAL; | ||
2699 | } | ||
2700 | } else { | ||
2701 | /* NTSC video mode | ||
2702 | * In the AGA chipset seems to be hardware bug with BPC3_BRDRBLNK | ||
2703 | * and NTSC activated, so than better let diwstop_h <= 1812 | ||
2704 | */ | ||
2705 | if (par->htotal != NTSC_HTOTAL) { | ||
2706 | DPRINTK("htotal invalid for ntsc\n"); | ||
2707 | return -EINVAL; | ||
2708 | } | ||
2709 | if (par->diwstrt_h < NTSC_DIWSTRT_H) { | ||
2710 | DPRINTK("diwstrt_h too low for ntsc\n"); | ||
2711 | return -EINVAL; | ||
2712 | } | ||
2713 | if (par->diwstrt_v < NTSC_DIWSTRT_V) { | ||
2714 | DPRINTK("diwstrt_v too low for ntsc\n"); | ||
2715 | return -EINVAL; | ||
2716 | } | ||
2717 | htotal = NTSC_HTOTAL>>clk_shift; | ||
2718 | vtotal = NTSC_VTOTAL>>1; | ||
2719 | if (!IS_OCS) { | ||
2720 | par->beamcon0 = 0; | ||
2721 | par->bplcon3 |= BPC3_BRDRBLNK; | ||
2722 | } else if (AMIGAHW_PRESENT(AGNUS_HR_PAL) || | ||
2723 | AMIGAHW_PRESENT(AGNUS_HR_NTSC)) { | ||
2724 | par->beamcon0 = 0; | ||
2725 | par->hsstop = 1; | ||
2726 | } else if (amiga_vblank != 60) { | ||
2727 | DPRINTK("ntsc not supported by this chipset\n"); | ||
2728 | return -EINVAL; | ||
2729 | } | ||
2730 | } | ||
2731 | if (IS_OCS) { | ||
2732 | if (par->diwstrt_h >= 1024 || par->diwstop_h < 1024 || | ||
2733 | par->diwstrt_v >= 512 || par->diwstop_v < 256) { | ||
2734 | DPRINTK("invalid position for display on ocs\n"); | ||
2735 | return -EINVAL; | ||
2736 | } | ||
2737 | } | ||
2738 | } else if (!IS_OCS) { | ||
2739 | /* Programmable video mode */ | ||
2740 | par->hsstrt = var->right_margin<<clk_shift; | ||
2741 | par->hsstop = (var->right_margin+var->hsync_len)<<clk_shift; | ||
2742 | par->diwstop_h = par->htotal - mod8(par->hsstrt) + 8 - (1 << clk_shift); | ||
2743 | if (!IS_AGA) | ||
2744 | par->diwstop_h = down4(par->diwstop_h) - 16; | ||
2745 | par->diwstrt_h = par->diwstop_h - xres_n; | ||
2746 | par->hbstop = par->diwstrt_h + 4; | ||
2747 | par->hbstrt = par->diwstop_h + 4; | ||
2748 | if (par->hbstrt >= par->htotal + 8) | ||
2749 | par->hbstrt -= par->htotal; | ||
2750 | par->hcenter = par->hsstrt + (par->htotal >> 1); | ||
2751 | par->vsstrt = var->lower_margin<<line_shift; | ||
2752 | par->vsstop = (var->lower_margin+var->vsync_len)<<line_shift; | ||
2753 | par->diwstop_v = par->vtotal; | ||
2754 | if ((par->vmode & FB_VMODE_MASK) == FB_VMODE_INTERLACED) | ||
2755 | par->diwstop_v -= 2; | ||
2756 | par->diwstrt_v = par->diwstop_v - yres_n; | ||
2757 | par->vbstop = par->diwstrt_v - 2; | ||
2758 | par->vbstrt = par->diwstop_v - 2; | ||
2759 | if (par->vtotal > 2048) { | ||
2760 | DPRINTK("vtotal too high\n"); | ||
2761 | return -EINVAL; | ||
2762 | } | ||
2763 | if (par->htotal > 2048) { | ||
2764 | DPRINTK("htotal too high\n"); | ||
2765 | return -EINVAL; | ||
2766 | } | ||
2767 | par->bplcon3 |= BPC3_EXTBLKEN; | ||
2768 | par->beamcon0 = BMC0_HARDDIS | BMC0_VARVBEN | BMC0_LOLDIS | | ||
2769 | BMC0_VARVSYEN | BMC0_VARHSYEN | BMC0_VARBEAMEN | | ||
2770 | BMC0_PAL | BMC0_VARCSYEN; | ||
2771 | if (var->sync & FB_SYNC_HOR_HIGH_ACT) | ||
2772 | par->beamcon0 |= BMC0_HSYTRUE; | ||
2773 | if (var->sync & FB_SYNC_VERT_HIGH_ACT) | ||
2774 | par->beamcon0 |= BMC0_VSYTRUE; | ||
2775 | if (var->sync & FB_SYNC_COMP_HIGH_ACT) | ||
2776 | par->beamcon0 |= BMC0_CSYTRUE; | ||
2777 | htotal = par->htotal>>clk_shift; | ||
2778 | vtotal = par->vtotal>>1; | ||
2779 | } else { | ||
2780 | DPRINTK("only broadcast modes possible for ocs\n"); | ||
2781 | return -EINVAL; | ||
2782 | } | ||
2783 | |||
2784 | /* | ||
2785 | * Checking the DMA timing | ||
2786 | */ | ||
2787 | |||
2788 | fconst = 16<<maxfmode<<clk_shift; | ||
2789 | |||
2790 | /* | ||
2791 | * smallest window start value without turn off other dma cycles | ||
2792 | * than sprite1-7, unless you change min_fstrt | ||
2793 | */ | ||
2794 | |||
2795 | |||
2796 | fsize = ((maxfmode+clk_shift <= 1) ? fconst : 64); | ||
2797 | fstrt = downx(fconst, par->diwstrt_h-4) - fsize; | ||
2798 | if (fstrt < min_fstrt) { | ||
2799 | DPRINTK("fetch start too low\n"); | ||
2800 | return -EINVAL; | ||
2801 | } | ||
2802 | |||
2803 | /* | ||
2804 | * smallest window start value where smooth scrolling is possible | ||
2805 | */ | ||
2806 | |||
2807 | fstrt = downx(fconst, par->diwstrt_h-fconst+(1<<clk_shift)-4) - fsize; | ||
2808 | if (fstrt < min_fstrt) | ||
2809 | par->vmode &= ~FB_VMODE_SMOOTH_XPAN; | ||
2810 | |||
2811 | maxfetchstop = down16(par->htotal - 80); | ||
2812 | |||
2813 | fstrt = downx(fconst, par->diwstrt_h-4) - 64 - fconst; | ||
2814 | fsize = upx(fconst, xres_n + modx(fconst, downx(1<<clk_shift, par->diwstrt_h-4))); | ||
2815 | if (fstrt + fsize > maxfetchstop) | ||
2816 | par->vmode &= ~FB_VMODE_SMOOTH_XPAN; | ||
2817 | |||
2818 | fsize = upx(fconst, xres_n); | ||
2819 | if (fstrt + fsize > maxfetchstop) { | ||
2820 | DPRINTK("fetch stop too high\n"); | ||
2821 | return -EINVAL; | ||
2822 | } | ||
2823 | |||
2824 | if (maxfmode + clk_shift <= 1) { | ||
2825 | fsize = up64(xres_n + fconst - 1); | ||
2826 | if (min_fstrt + fsize - 64 > maxfetchstop) | ||
2827 | par->vmode &= ~FB_VMODE_SMOOTH_XPAN; | ||
2828 | |||
2829 | fsize = up64(xres_n); | ||
2830 | if (min_fstrt + fsize - 64 > maxfetchstop) { | ||
2831 | DPRINTK("fetch size too high\n"); | ||
2832 | return -EINVAL; | ||
2833 | } | ||
2834 | |||
2835 | fsize -= 64; | ||
2836 | } else | ||
2837 | fsize -= fconst; | ||
2838 | |||
2839 | /* | ||
2840 | * Check if there is enough time to update the bitplane pointers for ywrap | ||
2841 | */ | ||
2842 | |||
2843 | if (par->htotal-fsize-64 < par->bpp*64) | ||
2844 | par->vmode &= ~FB_VMODE_YWRAP; | ||
2845 | |||
2846 | /* | ||
2847 | * Bitplane calculations and check the Memory Requirements | ||
2848 | */ | ||
2849 | |||
2850 | if (amifb_ilbm) { | ||
2851 | par->next_plane = div8(upx(16<<maxfmode, par->vxres)); | ||
2852 | par->next_line = par->bpp*par->next_plane; | ||
2853 | if (par->next_line * par->vyres > fb_info.fix.smem_len) { | ||
2854 | DPRINTK("too few video mem\n"); | ||
2855 | return -EINVAL; | ||
2856 | } | ||
2857 | } else { | ||
2858 | par->next_line = div8(upx(16<<maxfmode, par->vxres)); | ||
2859 | par->next_plane = par->vyres*par->next_line; | ||
2860 | if (par->next_plane * par->bpp > fb_info.fix.smem_len) { | ||
2861 | DPRINTK("too few video mem\n"); | ||
2862 | return -EINVAL; | ||
2863 | } | ||
2864 | } | ||
2865 | |||
2866 | /* | ||
2867 | * Hardware Register Values | ||
2868 | */ | ||
2869 | |||
2870 | par->bplcon0 = BPC0_COLOR | bplpixmode[clk_shift]; | ||
2871 | if (!IS_OCS) | ||
2872 | par->bplcon0 |= BPC0_ECSENA; | ||
2873 | if (par->bpp == 8) | ||
2874 | par->bplcon0 |= BPC0_BPU3; | ||
2875 | else | ||
2876 | par->bplcon0 |= par->bpp<<12; | ||
2877 | if (var->nonstd == FB_NONSTD_HAM) | ||
2878 | par->bplcon0 |= BPC0_HAM; | ||
2879 | if (var->sync & FB_SYNC_EXT) | ||
2880 | par->bplcon0 |= BPC0_ERSY; | ||
2881 | |||
2882 | if (IS_AGA) | ||
2883 | par->fmode = bplfetchmode[maxfmode]; | ||
2884 | |||
2885 | switch (par->vmode & FB_VMODE_MASK) { | ||
2886 | case FB_VMODE_INTERLACED: | ||
2887 | par->bplcon0 |= BPC0_LACE; | ||
2888 | break; | ||
2889 | case FB_VMODE_DOUBLE: | ||
2890 | if (IS_AGA) | ||
2891 | par->fmode |= FMODE_SSCAN2 | FMODE_BSCAN2; | ||
2892 | break; | ||
2893 | } | ||
2894 | |||
2895 | if (!((par->vmode ^ var->vmode) & FB_VMODE_YWRAP)) { | ||
2896 | par->xoffset = var->xoffset; | ||
2897 | par->yoffset = var->yoffset; | ||
2898 | if (par->vmode & FB_VMODE_YWRAP) { | ||
2899 | if (par->xoffset || par->yoffset < 0 || par->yoffset >= par->vyres) | ||
2900 | par->xoffset = par->yoffset = 0; | ||
2901 | } else { | ||
2902 | if (par->xoffset < 0 || par->xoffset > upx(16<<maxfmode, par->vxres-par->xres) || | ||
2903 | par->yoffset < 0 || par->yoffset > par->vyres-par->yres) | ||
2904 | par->xoffset = par->yoffset = 0; | ||
2905 | } | ||
2906 | } else | ||
2907 | par->xoffset = par->yoffset = 0; | ||
2908 | |||
2909 | par->crsr.crsr_x = par->crsr.crsr_y = 0; | ||
2910 | par->crsr.spot_x = par->crsr.spot_y = 0; | ||
2911 | par->crsr.height = par->crsr.width = 0; | ||
2912 | |||
2913 | return 0; | ||
2914 | } | ||
2915 | |||
2916 | /* | ||
2917 | * Fill the `var' structure based on the values in `par' and maybe | ||
2918 | * other values read out of the hardware. | ||
2919 | */ | ||
2920 | |||
2921 | static int ami_encode_var(struct fb_var_screeninfo *var, | ||
2922 | struct amifb_par *par) | ||
2923 | { | ||
2924 | u_short clk_shift, line_shift; | ||
2925 | |||
2926 | memset(var, 0, sizeof(struct fb_var_screeninfo)); | ||
2927 | |||
2928 | clk_shift = par->clk_shift; | ||
2929 | line_shift = par->line_shift; | ||
2930 | |||
2931 | var->xres = par->xres; | ||
2932 | var->yres = par->yres; | ||
2933 | var->xres_virtual = par->vxres; | ||
2934 | var->yres_virtual = par->vyres; | ||
2935 | var->xoffset = par->xoffset; | ||
2936 | var->yoffset = par->yoffset; | ||
2937 | |||
2938 | var->bits_per_pixel = par->bpp; | ||
2939 | var->grayscale = 0; | ||
2940 | |||
2941 | var->red.offset = 0; | ||
2942 | var->red.msb_right = 0; | ||
2943 | var->red.length = par->bpp; | ||
2944 | if (par->bplcon0 & BPC0_HAM) | ||
2945 | var->red.length -= 2; | ||
2946 | var->blue = var->green = var->red; | ||
2947 | var->transp.offset = 0; | ||
2948 | var->transp.length = 0; | ||
2949 | var->transp.msb_right = 0; | ||
2950 | |||
2951 | if (par->bplcon0 & BPC0_HAM) | ||
2952 | var->nonstd = FB_NONSTD_HAM; | ||
2953 | else | ||
2954 | var->nonstd = 0; | ||
2955 | var->activate = 0; | ||
2956 | |||
2957 | var->height = -1; | ||
2958 | var->width = -1; | ||
2959 | |||
2960 | var->pixclock = pixclock[clk_shift]; | ||
2961 | |||
2962 | if (IS_AGA && par->fmode & FMODE_BSCAN2) | ||
2963 | var->vmode = FB_VMODE_DOUBLE; | ||
2964 | else if (par->bplcon0 & BPC0_LACE) | ||
2965 | var->vmode = FB_VMODE_INTERLACED; | ||
2966 | else | ||
2967 | var->vmode = FB_VMODE_NONINTERLACED; | ||
2968 | |||
2969 | if (!IS_OCS && par->beamcon0 & BMC0_VARBEAMEN) { | ||
2970 | var->hsync_len = (par->hsstop-par->hsstrt)>>clk_shift; | ||
2971 | var->right_margin = par->hsstrt>>clk_shift; | ||
2972 | var->left_margin = (par->htotal>>clk_shift) - var->xres - var->right_margin - var->hsync_len; | ||
2973 | var->vsync_len = (par->vsstop-par->vsstrt)>>line_shift; | ||
2974 | var->lower_margin = par->vsstrt>>line_shift; | ||
2975 | var->upper_margin = (par->vtotal>>line_shift) - var->yres - var->lower_margin - var->vsync_len; | ||
2976 | var->sync = 0; | ||
2977 | if (par->beamcon0 & BMC0_HSYTRUE) | ||
2978 | var->sync |= FB_SYNC_HOR_HIGH_ACT; | ||
2979 | if (par->beamcon0 & BMC0_VSYTRUE) | ||
2980 | var->sync |= FB_SYNC_VERT_HIGH_ACT; | ||
2981 | if (par->beamcon0 & BMC0_CSYTRUE) | ||
2982 | var->sync |= FB_SYNC_COMP_HIGH_ACT; | ||
2983 | } else { | ||
2984 | var->sync = FB_SYNC_BROADCAST; | ||
2985 | var->hsync_len = (152>>clk_shift) + mod4(par->diwstop_h); | ||
2986 | var->right_margin = ((par->htotal - down4(par->diwstop_h))>>clk_shift) + var->hsync_len; | ||
2987 | var->left_margin = (par->htotal>>clk_shift) - var->xres - var->right_margin - var->hsync_len; | ||
2988 | var->vsync_len = 4>>line_shift; | ||
2989 | var->lower_margin = ((par->vtotal - par->diwstop_v)>>line_shift) + var->vsync_len; | ||
2990 | var->upper_margin = (((par->vtotal - 2)>>line_shift) + 1) - var->yres - | ||
2991 | var->lower_margin - var->vsync_len; | ||
2992 | } | ||
2993 | |||
2994 | if (par->bplcon0 & BPC0_ERSY) | ||
2995 | var->sync |= FB_SYNC_EXT; | ||
2996 | if (par->vmode & FB_VMODE_YWRAP) | ||
2997 | var->vmode |= FB_VMODE_YWRAP; | ||
2998 | |||
2999 | return 0; | ||
3000 | } | ||
3001 | |||
3002 | |||
3003 | /* | 3727 | /* |
3004 | * Pan or Wrap the Display | 3728 | * Enable Display DMA |
3005 | * | ||
3006 | * This call looks only at xoffset, yoffset and the FB_VMODE_YWRAP flag | ||
3007 | * in `var'. | ||
3008 | */ | ||
3009 | |||
3010 | static void ami_pan_var(struct fb_var_screeninfo *var) | ||
3011 | { | ||
3012 | struct amifb_par *par = ¤tpar; | ||
3013 | |||
3014 | par->xoffset = var->xoffset; | ||
3015 | par->yoffset = var->yoffset; | ||
3016 | if (var->vmode & FB_VMODE_YWRAP) | ||
3017 | par->vmode |= FB_VMODE_YWRAP; | ||
3018 | else | ||
3019 | par->vmode &= ~FB_VMODE_YWRAP; | ||
3020 | |||
3021 | do_vmode_pan = 0; | ||
3022 | ami_update_par(); | ||
3023 | do_vmode_pan = 1; | ||
3024 | } | ||
3025 | |||
3026 | /* | ||
3027 | * Update hardware | ||
3028 | */ | ||
3029 | |||
3030 | static int ami_update_par(void) | ||
3031 | { | ||
3032 | struct amifb_par *par = ¤tpar; | ||
3033 | short clk_shift, vshift, fstrt, fsize, fstop, fconst, shift, move, mod; | ||
3034 | |||
3035 | clk_shift = par->clk_shift; | ||
3036 | |||
3037 | if (!(par->vmode & FB_VMODE_SMOOTH_XPAN)) | ||
3038 | par->xoffset = upx(16<<maxfmode, par->xoffset); | ||
3039 | |||
3040 | fconst = 16<<maxfmode<<clk_shift; | ||
3041 | vshift = modx(16<<maxfmode, par->xoffset); | ||
3042 | fstrt = par->diwstrt_h - (vshift<<clk_shift) - 4; | ||
3043 | fsize = (par->xres+vshift)<<clk_shift; | ||
3044 | shift = modx(fconst, fstrt); | ||
3045 | move = downx(2<<maxfmode, div8(par->xoffset)); | ||
3046 | if (maxfmode + clk_shift > 1) { | ||
3047 | fstrt = downx(fconst, fstrt) - 64; | ||
3048 | fsize = upx(fconst, fsize); | ||
3049 | fstop = fstrt + fsize - fconst; | ||
3050 | } else { | ||
3051 | mod = fstrt = downx(fconst, fstrt) - fconst; | ||
3052 | fstop = fstrt + upx(fconst, fsize) - 64; | ||
3053 | fsize = up64(fsize); | ||
3054 | fstrt = fstop - fsize + 64; | ||
3055 | if (fstrt < min_fstrt) { | ||
3056 | fstop += min_fstrt - fstrt; | ||
3057 | fstrt = min_fstrt; | ||
3058 | } | ||
3059 | move = move - div8((mod-fstrt)>>clk_shift); | ||
3060 | } | ||
3061 | mod = par->next_line - div8(fsize>>clk_shift); | ||
3062 | par->ddfstrt = fstrt; | ||
3063 | par->ddfstop = fstop; | ||
3064 | par->bplcon1 = hscroll2hw(shift); | ||
3065 | par->bpl2mod = mod; | ||
3066 | if (par->bplcon0 & BPC0_LACE) | ||
3067 | par->bpl2mod += par->next_line; | ||
3068 | if (IS_AGA && (par->fmode & FMODE_BSCAN2)) | ||
3069 | par->bpl1mod = -div8(fsize>>clk_shift); | ||
3070 | else | ||
3071 | par->bpl1mod = par->bpl2mod; | ||
3072 | |||
3073 | if (par->yoffset) { | ||
3074 | par->bplpt0 = fb_info.fix.smem_start + par->next_line*par->yoffset + move; | ||
3075 | if (par->vmode & FB_VMODE_YWRAP) { | ||
3076 | if (par->yoffset > par->vyres-par->yres) { | ||
3077 | par->bplpt0wrap = fb_info.fix.smem_start + move; | ||
3078 | if (par->bplcon0 & BPC0_LACE && mod2(par->diwstrt_v+par->vyres-par->yoffset)) | ||
3079 | par->bplpt0wrap += par->next_line; | ||
3080 | } | ||
3081 | } | ||
3082 | } else | ||
3083 | par->bplpt0 = fb_info.fix.smem_start + move; | ||
3084 | |||
3085 | if (par->bplcon0 & BPC0_LACE && mod2(par->diwstrt_v)) | ||
3086 | par->bplpt0 += par->next_line; | ||
3087 | |||
3088 | return 0; | ||
3089 | } | ||
3090 | |||
3091 | |||
3092 | /* | ||
3093 | * Set a single color register. The values supplied are already | ||
3094 | * rounded down to the hardware's capabilities (according to the | ||
3095 | * entries in the var structure). Return != 0 for invalid regno. | ||
3096 | */ | ||
3097 | |||
3098 | static int amifb_setcolreg(u_int regno, u_int red, u_int green, u_int blue, | ||
3099 | u_int transp, struct fb_info *info) | ||
3100 | { | ||
3101 | if (IS_AGA) { | ||
3102 | if (regno > 255) | ||
3103 | return 1; | ||
3104 | } else if (currentpar.bplcon0 & BPC0_SHRES) { | ||
3105 | if (regno > 3) | ||
3106 | return 1; | ||
3107 | } else { | ||
3108 | if (regno > 31) | ||
3109 | return 1; | ||
3110 | } | ||
3111 | red >>= 8; | ||
3112 | green >>= 8; | ||
3113 | blue >>= 8; | ||
3114 | if (!regno) { | ||
3115 | red0 = red; | ||
3116 | green0 = green; | ||
3117 | blue0 = blue; | ||
3118 | } | ||
3119 | |||
3120 | /* | ||
3121 | * Update the corresponding Hardware Color Register, unless it's Color | ||
3122 | * Register 0 and the screen is blanked. | ||
3123 | * | ||
3124 | * VBlank is switched off to protect bplcon3 or ecs_palette[] from | ||
3125 | * being changed by ami_do_blank() during the VBlank. | ||
3126 | */ | ||
3127 | |||
3128 | if (regno || !is_blanked) { | ||
3129 | #if defined(CONFIG_FB_AMIGA_AGA) | ||
3130 | if (IS_AGA) { | ||
3131 | u_short bplcon3 = currentpar.bplcon3; | ||
3132 | VBlankOff(); | ||
3133 | custom.bplcon3 = bplcon3 | (regno<<8 & 0xe000); | ||
3134 | custom.color[regno&31] = rgb2hw8_high(red, green, blue); | ||
3135 | custom.bplcon3 = bplcon3 | (regno<<8 & 0xe000) | BPC3_LOCT; | ||
3136 | custom.color[regno&31] = rgb2hw8_low(red, green, blue); | ||
3137 | custom.bplcon3 = bplcon3; | ||
3138 | VBlankOn(); | ||
3139 | } else | ||
3140 | #endif | ||
3141 | #if defined(CONFIG_FB_AMIGA_ECS) | ||
3142 | if (currentpar.bplcon0 & BPC0_SHRES) { | ||
3143 | u_short color, mask; | ||
3144 | int i; | ||
3145 | |||
3146 | mask = 0x3333; | ||
3147 | color = rgb2hw2(red, green, blue); | ||
3148 | VBlankOff(); | ||
3149 | for (i = regno+12; i >= (int)regno; i -= 4) | ||
3150 | custom.color[i] = ecs_palette[i] = (ecs_palette[i] & mask) | color; | ||
3151 | mask <<=2; color >>= 2; | ||
3152 | regno = down16(regno)+mul4(mod4(regno)); | ||
3153 | for (i = regno+3; i >= (int)regno; i--) | ||
3154 | custom.color[i] = ecs_palette[i] = (ecs_palette[i] & mask) | color; | ||
3155 | VBlankOn(); | ||
3156 | } else | ||
3157 | #endif | ||
3158 | custom.color[regno] = rgb2hw4(red, green, blue); | ||
3159 | } | ||
3160 | return 0; | ||
3161 | } | ||
3162 | |||
3163 | static void ami_update_display(void) | ||
3164 | { | ||
3165 | struct amifb_par *par = ¤tpar; | ||
3166 | |||
3167 | custom.bplcon1 = par->bplcon1; | ||
3168 | custom.bpl1mod = par->bpl1mod; | ||
3169 | custom.bpl2mod = par->bpl2mod; | ||
3170 | custom.ddfstrt = ddfstrt2hw(par->ddfstrt); | ||
3171 | custom.ddfstop = ddfstop2hw(par->ddfstop); | ||
3172 | } | ||
3173 | |||
3174 | /* | ||
3175 | * Change the video mode (called by VBlank interrupt) | ||
3176 | */ | ||
3177 | |||
3178 | static void ami_init_display(void) | ||
3179 | { | ||
3180 | struct amifb_par *par = ¤tpar; | ||
3181 | int i; | ||
3182 | |||
3183 | custom.bplcon0 = par->bplcon0 & ~BPC0_LACE; | ||
3184 | custom.bplcon2 = (IS_OCS ? 0 : BPC2_KILLEHB) | BPC2_PF2P2 | BPC2_PF1P2; | ||
3185 | if (!IS_OCS) { | ||
3186 | custom.bplcon3 = par->bplcon3; | ||
3187 | if (IS_AGA) | ||
3188 | custom.bplcon4 = BPC4_ESPRM4 | BPC4_OSPRM4; | ||
3189 | if (par->beamcon0 & BMC0_VARBEAMEN) { | ||
3190 | custom.htotal = htotal2hw(par->htotal); | ||
3191 | custom.hbstrt = hbstrt2hw(par->hbstrt); | ||
3192 | custom.hbstop = hbstop2hw(par->hbstop); | ||
3193 | custom.hsstrt = hsstrt2hw(par->hsstrt); | ||
3194 | custom.hsstop = hsstop2hw(par->hsstop); | ||
3195 | custom.hcenter = hcenter2hw(par->hcenter); | ||
3196 | custom.vtotal = vtotal2hw(par->vtotal); | ||
3197 | custom.vbstrt = vbstrt2hw(par->vbstrt); | ||
3198 | custom.vbstop = vbstop2hw(par->vbstop); | ||
3199 | custom.vsstrt = vsstrt2hw(par->vsstrt); | ||
3200 | custom.vsstop = vsstop2hw(par->vsstop); | ||
3201 | } | ||
3202 | } | ||
3203 | if (!IS_OCS || par->hsstop) | ||
3204 | custom.beamcon0 = par->beamcon0; | ||
3205 | if (IS_AGA) | ||
3206 | custom.fmode = par->fmode; | ||
3207 | |||
3208 | /* | ||
3209 | * The minimum period for audio depends on htotal | ||
3210 | */ | ||
3211 | |||
3212 | amiga_audio_min_period = div16(par->htotal); | ||
3213 | |||
3214 | is_lace = par->bplcon0 & BPC0_LACE ? 1 : 0; | ||
3215 | #if 1 | ||
3216 | if (is_lace) { | ||
3217 | i = custom.vposr >> 15; | ||
3218 | } else { | ||
3219 | custom.vposw = custom.vposr | 0x8000; | ||
3220 | i = 1; | ||
3221 | } | ||
3222 | #else | ||
3223 | i = 1; | ||
3224 | custom.vposw = custom.vposr | 0x8000; | ||
3225 | #endif | ||
3226 | custom.cop2lc = (u_short *)ZTWO_PADDR(copdisplay.list[currentcop][i]); | ||
3227 | } | ||
3228 | |||
3229 | /* | ||
3230 | * (Un)Blank the screen (called by VBlank interrupt) | ||
3231 | */ | 3729 | */ |
3730 | custom.dmacon = DMAF_SETCLR | DMAF_MASTER | DMAF_RASTER | DMAF_COPPER | | ||
3731 | DMAF_BLITTER | DMAF_SPRITE; | ||
3232 | 3732 | ||
3233 | static void ami_do_blank(void) | 3733 | err = request_irq(IRQ_AMIGA_COPPER, amifb_interrupt, 0, |
3234 | { | 3734 | "fb vertb handler", info->par); |
3235 | struct amifb_par *par = ¤tpar; | 3735 | if (err) |
3236 | #if defined(CONFIG_FB_AMIGA_AGA) | 3736 | goto disable_dma; |
3237 | u_short bplcon3 = par->bplcon3; | ||
3238 | #endif | ||
3239 | u_char red, green, blue; | ||
3240 | |||
3241 | if (do_blank > 0) { | ||
3242 | custom.dmacon = DMAF_RASTER | DMAF_SPRITE; | ||
3243 | red = green = blue = 0; | ||
3244 | if (!IS_OCS && do_blank > 1) { | ||
3245 | switch (do_blank) { | ||
3246 | case FB_BLANK_VSYNC_SUSPEND: | ||
3247 | custom.hsstrt = hsstrt2hw(par->hsstrt); | ||
3248 | custom.hsstop = hsstop2hw(par->hsstop); | ||
3249 | custom.vsstrt = vsstrt2hw(par->vtotal+4); | ||
3250 | custom.vsstop = vsstop2hw(par->vtotal+4); | ||
3251 | break; | ||
3252 | case FB_BLANK_HSYNC_SUSPEND: | ||
3253 | custom.hsstrt = hsstrt2hw(par->htotal+16); | ||
3254 | custom.hsstop = hsstop2hw(par->htotal+16); | ||
3255 | custom.vsstrt = vsstrt2hw(par->vsstrt); | ||
3256 | custom.vsstop = vsstrt2hw(par->vsstop); | ||
3257 | break; | ||
3258 | case FB_BLANK_POWERDOWN: | ||
3259 | custom.hsstrt = hsstrt2hw(par->htotal+16); | ||
3260 | custom.hsstop = hsstop2hw(par->htotal+16); | ||
3261 | custom.vsstrt = vsstrt2hw(par->vtotal+4); | ||
3262 | custom.vsstop = vsstop2hw(par->vtotal+4); | ||
3263 | break; | ||
3264 | } | ||
3265 | if (!(par->beamcon0 & BMC0_VARBEAMEN)) { | ||
3266 | custom.htotal = htotal2hw(par->htotal); | ||
3267 | custom.vtotal = vtotal2hw(par->vtotal); | ||
3268 | custom.beamcon0 = BMC0_HARDDIS | BMC0_VARBEAMEN | | ||
3269 | BMC0_VARVSYEN | BMC0_VARHSYEN | BMC0_VARCSYEN; | ||
3270 | } | ||
3271 | } | ||
3272 | } else { | ||
3273 | custom.dmacon = DMAF_SETCLR | DMAF_RASTER | DMAF_SPRITE; | ||
3274 | red = red0; | ||
3275 | green = green0; | ||
3276 | blue = blue0; | ||
3277 | if (!IS_OCS) { | ||
3278 | custom.hsstrt = hsstrt2hw(par->hsstrt); | ||
3279 | custom.hsstop = hsstop2hw(par->hsstop); | ||
3280 | custom.vsstrt = vsstrt2hw(par->vsstrt); | ||
3281 | custom.vsstop = vsstop2hw(par->vsstop); | ||
3282 | custom.beamcon0 = par->beamcon0; | ||
3283 | } | ||
3284 | } | ||
3285 | #if defined(CONFIG_FB_AMIGA_AGA) | ||
3286 | if (IS_AGA) { | ||
3287 | custom.bplcon3 = bplcon3; | ||
3288 | custom.color[0] = rgb2hw8_high(red, green, blue); | ||
3289 | custom.bplcon3 = bplcon3 | BPC3_LOCT; | ||
3290 | custom.color[0] = rgb2hw8_low(red, green, blue); | ||
3291 | custom.bplcon3 = bplcon3; | ||
3292 | } else | ||
3293 | #endif | ||
3294 | #if defined(CONFIG_FB_AMIGA_ECS) | ||
3295 | if (par->bplcon0 & BPC0_SHRES) { | ||
3296 | u_short color, mask; | ||
3297 | int i; | ||
3298 | |||
3299 | mask = 0x3333; | ||
3300 | color = rgb2hw2(red, green, blue); | ||
3301 | for (i = 12; i >= 0; i -= 4) | ||
3302 | custom.color[i] = ecs_palette[i] = (ecs_palette[i] & mask) | color; | ||
3303 | mask <<=2; color >>= 2; | ||
3304 | for (i = 3; i >= 0; i--) | ||
3305 | custom.color[i] = ecs_palette[i] = (ecs_palette[i] & mask) | color; | ||
3306 | } else | ||
3307 | #endif | ||
3308 | custom.color[0] = rgb2hw4(red, green, blue); | ||
3309 | is_blanked = do_blank > 0 ? do_blank : 0; | ||
3310 | } | ||
3311 | |||
3312 | static int ami_get_fix_cursorinfo(struct fb_fix_cursorinfo *fix) | ||
3313 | { | ||
3314 | struct amifb_par *par = ¤tpar; | ||
3315 | |||
3316 | fix->crsr_width = fix->crsr_xsize = par->crsr.width; | ||
3317 | fix->crsr_height = fix->crsr_ysize = par->crsr.height; | ||
3318 | fix->crsr_color1 = 17; | ||
3319 | fix->crsr_color2 = 18; | ||
3320 | return 0; | ||
3321 | } | ||
3322 | |||
3323 | static int ami_get_var_cursorinfo(struct fb_var_cursorinfo *var, u_char __user *data) | ||
3324 | { | ||
3325 | struct amifb_par *par = ¤tpar; | ||
3326 | register u_short *lspr, *sspr; | ||
3327 | #ifdef __mc68000__ | ||
3328 | register u_long datawords asm ("d2"); | ||
3329 | #else | ||
3330 | register u_long datawords; | ||
3331 | #endif | ||
3332 | register short delta; | ||
3333 | register u_char color; | ||
3334 | short height, width, bits, words; | ||
3335 | int size, alloc; | ||
3336 | |||
3337 | size = par->crsr.height*par->crsr.width; | ||
3338 | alloc = var->height*var->width; | ||
3339 | var->height = par->crsr.height; | ||
3340 | var->width = par->crsr.width; | ||
3341 | var->xspot = par->crsr.spot_x; | ||
3342 | var->yspot = par->crsr.spot_y; | ||
3343 | if (size > var->height*var->width) | ||
3344 | return -ENAMETOOLONG; | ||
3345 | if (!access_ok(VERIFY_WRITE, data, size)) | ||
3346 | return -EFAULT; | ||
3347 | delta = 1<<par->crsr.fmode; | ||
3348 | lspr = lofsprite + (delta<<1); | ||
3349 | if (par->bplcon0 & BPC0_LACE) | ||
3350 | sspr = shfsprite + (delta<<1); | ||
3351 | else | ||
3352 | sspr = NULL; | ||
3353 | for (height = (short)var->height-1; height >= 0; height--) { | ||
3354 | bits = 0; words = delta; datawords = 0; | ||
3355 | for (width = (short)var->width-1; width >= 0; width--) { | ||
3356 | if (bits == 0) { | ||
3357 | bits = 16; --words; | ||
3358 | #ifdef __mc68000__ | ||
3359 | asm volatile ("movew %1@(%3:w:2),%0 ; swap %0 ; movew %1@+,%0" | ||
3360 | : "=d" (datawords), "=a" (lspr) : "1" (lspr), "d" (delta)); | ||
3361 | #else | ||
3362 | datawords = (*(lspr+delta) << 16) | (*lspr++); | ||
3363 | #endif | ||
3364 | } | ||
3365 | --bits; | ||
3366 | #ifdef __mc68000__ | ||
3367 | asm volatile ( | ||
3368 | "clrb %0 ; swap %1 ; lslw #1,%1 ; roxlb #1,%0 ; " | ||
3369 | "swap %1 ; lslw #1,%1 ; roxlb #1,%0" | ||
3370 | : "=d" (color), "=d" (datawords) : "1" (datawords)); | ||
3371 | #else | ||
3372 | color = (((datawords >> 30) & 2) | ||
3373 | | ((datawords >> 15) & 1)); | ||
3374 | datawords <<= 1; | ||
3375 | #endif | ||
3376 | put_user(color, data++); | ||
3377 | } | ||
3378 | if (bits > 0) { | ||
3379 | --words; ++lspr; | ||
3380 | } | ||
3381 | while (--words >= 0) | ||
3382 | ++lspr; | ||
3383 | #ifdef __mc68000__ | ||
3384 | asm volatile ("lea %0@(%4:w:2),%0 ; tstl %1 ; jeq 1f ; exg %0,%1\n1:" | ||
3385 | : "=a" (lspr), "=a" (sspr) : "0" (lspr), "1" (sspr), "d" (delta)); | ||
3386 | #else | ||
3387 | lspr += delta; | ||
3388 | if (sspr) { | ||
3389 | u_short *tmp = lspr; | ||
3390 | lspr = sspr; | ||
3391 | sspr = tmp; | ||
3392 | } | ||
3393 | #endif | ||
3394 | } | ||
3395 | return 0; | ||
3396 | } | ||
3397 | |||
3398 | static int ami_set_var_cursorinfo(struct fb_var_cursorinfo *var, u_char __user *data) | ||
3399 | { | ||
3400 | struct amifb_par *par = ¤tpar; | ||
3401 | register u_short *lspr, *sspr; | ||
3402 | #ifdef __mc68000__ | ||
3403 | register u_long datawords asm ("d2"); | ||
3404 | #else | ||
3405 | register u_long datawords; | ||
3406 | #endif | ||
3407 | register short delta; | ||
3408 | u_short fmode; | ||
3409 | short height, width, bits, words; | ||
3410 | 3737 | ||
3411 | if (!var->width) | 3738 | err = fb_alloc_cmap(&info->cmap, 1 << info->var.bits_per_pixel, 0); |
3412 | return -EINVAL; | 3739 | if (err) |
3413 | else if (var->width <= 16) | 3740 | goto free_irq; |
3414 | fmode = TAG_FMODE_1; | ||
3415 | else if (var->width <= 32) | ||
3416 | fmode = TAG_FMODE_2; | ||
3417 | else if (var->width <= 64) | ||
3418 | fmode = TAG_FMODE_4; | ||
3419 | else | ||
3420 | return -EINVAL; | ||
3421 | if (fmode > maxfmode) | ||
3422 | return -EINVAL; | ||
3423 | if (!var->height) | ||
3424 | return -EINVAL; | ||
3425 | if (!access_ok(VERIFY_READ, data, var->width*var->height)) | ||
3426 | return -EFAULT; | ||
3427 | delta = 1<<fmode; | ||
3428 | lofsprite = shfsprite = (u_short *)spritememory; | ||
3429 | lspr = lofsprite + (delta<<1); | ||
3430 | if (par->bplcon0 & BPC0_LACE) { | ||
3431 | if (((var->height+4)<<fmode<<2) > SPRITEMEMSIZE) | ||
3432 | return -EINVAL; | ||
3433 | memset(lspr, 0, (var->height+4)<<fmode<<2); | ||
3434 | shfsprite += ((var->height+5)&-2)<<fmode; | ||
3435 | sspr = shfsprite + (delta<<1); | ||
3436 | } else { | ||
3437 | if (((var->height+2)<<fmode<<2) > SPRITEMEMSIZE) | ||
3438 | return -EINVAL; | ||
3439 | memset(lspr, 0, (var->height+2)<<fmode<<2); | ||
3440 | sspr = NULL; | ||
3441 | } | ||
3442 | for (height = (short)var->height-1; height >= 0; height--) { | ||
3443 | bits = 16; words = delta; datawords = 0; | ||
3444 | for (width = (short)var->width-1; width >= 0; width--) { | ||
3445 | unsigned long tdata = 0; | ||
3446 | get_user(tdata, data); | ||
3447 | data++; | ||
3448 | #ifdef __mc68000__ | ||
3449 | asm volatile ( | ||
3450 | "lsrb #1,%2 ; roxlw #1,%0 ; swap %0 ; " | ||
3451 | "lsrb #1,%2 ; roxlw #1,%0 ; swap %0" | ||
3452 | : "=d" (datawords) | ||
3453 | : "0" (datawords), "d" (tdata)); | ||
3454 | #else | ||
3455 | datawords = ((datawords << 1) & 0xfffefffe); | ||
3456 | datawords |= tdata & 1; | ||
3457 | datawords |= (tdata & 2) << (16-1); | ||
3458 | #endif | ||
3459 | if (--bits == 0) { | ||
3460 | bits = 16; --words; | ||
3461 | #ifdef __mc68000__ | ||
3462 | asm volatile ("swap %2 ; movew %2,%0@(%3:w:2) ; swap %2 ; movew %2,%0@+" | ||
3463 | : "=a" (lspr) : "0" (lspr), "d" (datawords), "d" (delta)); | ||
3464 | #else | ||
3465 | *(lspr+delta) = (u_short) (datawords >> 16); | ||
3466 | *lspr++ = (u_short) (datawords & 0xffff); | ||
3467 | #endif | ||
3468 | } | ||
3469 | } | ||
3470 | if (bits < 16) { | ||
3471 | --words; | ||
3472 | #ifdef __mc68000__ | ||
3473 | asm volatile ( | ||
3474 | "swap %2 ; lslw %4,%2 ; movew %2,%0@(%3:w:2) ; " | ||
3475 | "swap %2 ; lslw %4,%2 ; movew %2,%0@+" | ||
3476 | : "=a" (lspr) : "0" (lspr), "d" (datawords), "d" (delta), "d" (bits)); | ||
3477 | #else | ||
3478 | *(lspr+delta) = (u_short) (datawords >> (16+bits)); | ||
3479 | *lspr++ = (u_short) ((datawords & 0x0000ffff) >> bits); | ||
3480 | #endif | ||
3481 | } | ||
3482 | while (--words >= 0) { | ||
3483 | #ifdef __mc68000__ | ||
3484 | asm volatile ("moveql #0,%%d0 ; movew %%d0,%0@(%2:w:2) ; movew %%d0,%0@+" | ||
3485 | : "=a" (lspr) : "0" (lspr), "d" (delta) : "d0"); | ||
3486 | #else | ||
3487 | *(lspr+delta) = 0; | ||
3488 | *lspr++ = 0; | ||
3489 | #endif | ||
3490 | } | ||
3491 | #ifdef __mc68000__ | ||
3492 | asm volatile ("lea %0@(%4:w:2),%0 ; tstl %1 ; jeq 1f ; exg %0,%1\n1:" | ||
3493 | : "=a" (lspr), "=a" (sspr) : "0" (lspr), "1" (sspr), "d" (delta)); | ||
3494 | #else | ||
3495 | lspr += delta; | ||
3496 | if (sspr) { | ||
3497 | u_short *tmp = lspr; | ||
3498 | lspr = sspr; | ||
3499 | sspr = tmp; | ||
3500 | } | ||
3501 | #endif | ||
3502 | } | ||
3503 | par->crsr.height = var->height; | ||
3504 | par->crsr.width = var->width; | ||
3505 | par->crsr.spot_x = var->xspot; | ||
3506 | par->crsr.spot_y = var->yspot; | ||
3507 | par->crsr.fmode = fmode; | ||
3508 | if (IS_AGA) { | ||
3509 | par->fmode &= ~(FMODE_SPAGEM | FMODE_SPR32); | ||
3510 | par->fmode |= sprfetchmode[fmode]; | ||
3511 | custom.fmode = par->fmode; | ||
3512 | } | ||
3513 | return 0; | ||
3514 | } | ||
3515 | 3741 | ||
3516 | static int ami_get_cursorstate(struct fb_cursorstate *state) | 3742 | dev_set_drvdata(&pdev->dev, info); |
3517 | { | ||
3518 | struct amifb_par *par = ¤tpar; | ||
3519 | 3743 | ||
3520 | state->xoffset = par->crsr.crsr_x; | 3744 | err = register_framebuffer(info); |
3521 | state->yoffset = par->crsr.crsr_y; | 3745 | if (err) |
3522 | state->mode = cursormode; | 3746 | goto unset_drvdata; |
3523 | return 0; | ||
3524 | } | ||
3525 | 3747 | ||
3526 | static int ami_set_cursorstate(struct fb_cursorstate *state) | 3748 | printk("fb%d: %s frame buffer device, using %dK of video memory\n", |
3527 | { | 3749 | info->node, info->fix.id, info->fix.smem_len>>10); |
3528 | struct amifb_par *par = ¤tpar; | ||
3529 | 3750 | ||
3530 | par->crsr.crsr_x = state->xoffset; | ||
3531 | par->crsr.crsr_y = state->yoffset; | ||
3532 | if ((cursormode = state->mode) == FB_CURSOR_OFF) | ||
3533 | cursorstate = -1; | ||
3534 | do_cursor = 1; | ||
3535 | return 0; | 3751 | return 0; |
3536 | } | ||
3537 | |||
3538 | static void ami_set_sprite(void) | ||
3539 | { | ||
3540 | struct amifb_par *par = ¤tpar; | ||
3541 | copins *copl, *cops; | ||
3542 | u_short hs, vs, ve; | ||
3543 | u_long pl, ps, pt; | ||
3544 | short mx, my; | ||
3545 | |||
3546 | cops = copdisplay.list[currentcop][0]; | ||
3547 | copl = copdisplay.list[currentcop][1]; | ||
3548 | ps = pl = ZTWO_PADDR(dummysprite); | ||
3549 | mx = par->crsr.crsr_x-par->crsr.spot_x; | ||
3550 | my = par->crsr.crsr_y-par->crsr.spot_y; | ||
3551 | if (!(par->vmode & FB_VMODE_YWRAP)) { | ||
3552 | mx -= par->xoffset; | ||
3553 | my -= par->yoffset; | ||
3554 | } | ||
3555 | if (!is_blanked && cursorstate > 0 && par->crsr.height > 0 && | ||
3556 | mx > -(short)par->crsr.width && mx < par->xres && | ||
3557 | my > -(short)par->crsr.height && my < par->yres) { | ||
3558 | pl = ZTWO_PADDR(lofsprite); | ||
3559 | hs = par->diwstrt_h + (mx<<par->clk_shift) - 4; | ||
3560 | vs = par->diwstrt_v + (my<<par->line_shift); | ||
3561 | ve = vs + (par->crsr.height<<par->line_shift); | ||
3562 | if (par->bplcon0 & BPC0_LACE) { | ||
3563 | ps = ZTWO_PADDR(shfsprite); | ||
3564 | lofsprite[0] = spr2hw_pos(vs, hs); | ||
3565 | shfsprite[0] = spr2hw_pos(vs+1, hs); | ||
3566 | if (mod2(vs)) { | ||
3567 | lofsprite[1<<par->crsr.fmode] = spr2hw_ctl(vs, hs, ve); | ||
3568 | shfsprite[1<<par->crsr.fmode] = spr2hw_ctl(vs+1, hs, ve+1); | ||
3569 | pt = pl; pl = ps; ps = pt; | ||
3570 | } else { | ||
3571 | lofsprite[1<<par->crsr.fmode] = spr2hw_ctl(vs, hs, ve+1); | ||
3572 | shfsprite[1<<par->crsr.fmode] = spr2hw_ctl(vs+1, hs, ve); | ||
3573 | } | ||
3574 | } else { | ||
3575 | lofsprite[0] = spr2hw_pos(vs, hs) | (IS_AGA && (par->fmode & FMODE_BSCAN2) ? 0x80 : 0); | ||
3576 | lofsprite[1<<par->crsr.fmode] = spr2hw_ctl(vs, hs, ve); | ||
3577 | } | ||
3578 | } | ||
3579 | copl[cop_spr0ptrh].w[1] = highw(pl); | ||
3580 | copl[cop_spr0ptrl].w[1] = loww(pl); | ||
3581 | if (par->bplcon0 & BPC0_LACE) { | ||
3582 | cops[cop_spr0ptrh].w[1] = highw(ps); | ||
3583 | cops[cop_spr0ptrl].w[1] = loww(ps); | ||
3584 | } | ||
3585 | } | ||
3586 | |||
3587 | |||
3588 | /* | ||
3589 | * Initialise the Copper Initialisation List | ||
3590 | */ | ||
3591 | |||
3592 | static void __init ami_init_copper(void) | ||
3593 | { | ||
3594 | copins *cop = copdisplay.init; | ||
3595 | u_long p; | ||
3596 | int i; | ||
3597 | |||
3598 | if (!IS_OCS) { | ||
3599 | (cop++)->l = CMOVE(BPC0_COLOR | BPC0_SHRES | BPC0_ECSENA, bplcon0); | ||
3600 | (cop++)->l = CMOVE(0x0181, diwstrt); | ||
3601 | (cop++)->l = CMOVE(0x0281, diwstop); | ||
3602 | (cop++)->l = CMOVE(0x0000, diwhigh); | ||
3603 | } else | ||
3604 | (cop++)->l = CMOVE(BPC0_COLOR, bplcon0); | ||
3605 | p = ZTWO_PADDR(dummysprite); | ||
3606 | for (i = 0; i < 8; i++) { | ||
3607 | (cop++)->l = CMOVE(0, spr[i].pos); | ||
3608 | (cop++)->l = CMOVE(highw(p), sprpt[i]); | ||
3609 | (cop++)->l = CMOVE2(loww(p), sprpt[i]); | ||
3610 | } | ||
3611 | |||
3612 | (cop++)->l = CMOVE(IF_SETCLR | IF_COPER, intreq); | ||
3613 | copdisplay.wait = cop; | ||
3614 | (cop++)->l = CEND; | ||
3615 | (cop++)->l = CMOVE(0, copjmp2); | ||
3616 | cop->l = CEND; | ||
3617 | |||
3618 | custom.cop1lc = (u_short *)ZTWO_PADDR(copdisplay.init); | ||
3619 | custom.copjmp1 = 0; | ||
3620 | } | ||
3621 | 3752 | ||
3622 | static void ami_reinit_copper(void) | 3753 | unset_drvdata: |
3623 | { | 3754 | dev_set_drvdata(&pdev->dev, NULL); |
3624 | struct amifb_par *par = ¤tpar; | 3755 | fb_dealloc_cmap(&info->cmap); |
3625 | 3756 | free_irq: | |
3626 | copdisplay.init[cip_bplcon0].w[1] = ~(BPC0_BPU3 | BPC0_BPU2 | BPC0_BPU1 | BPC0_BPU0) & par->bplcon0; | 3757 | free_irq(IRQ_AMIGA_COPPER, info->par); |
3627 | copdisplay.wait->l = CWAIT(32, par->diwstrt_v-4); | 3758 | disable_dma: |
3759 | custom.dmacon = DMAF_ALL | DMAF_MASTER; | ||
3760 | if (videomemory) | ||
3761 | iounmap((void *)videomemory); | ||
3762 | chipfree(); | ||
3763 | release: | ||
3764 | framebuffer_release(info); | ||
3765 | return err; | ||
3628 | } | 3766 | } |
3629 | 3767 | ||
3630 | /* | ||
3631 | * Build the Copper List | ||
3632 | */ | ||
3633 | |||
3634 | static void ami_build_copper(void) | ||
3635 | { | ||
3636 | struct amifb_par *par = ¤tpar; | ||
3637 | copins *copl, *cops; | ||
3638 | u_long p; | ||
3639 | |||
3640 | currentcop = 1 - currentcop; | ||
3641 | |||
3642 | copl = copdisplay.list[currentcop][1]; | ||
3643 | |||
3644 | (copl++)->l = CWAIT(0, 10); | ||
3645 | (copl++)->l = CMOVE(par->bplcon0, bplcon0); | ||
3646 | (copl++)->l = CMOVE(0, sprpt[0]); | ||
3647 | (copl++)->l = CMOVE2(0, sprpt[0]); | ||
3648 | |||
3649 | if (par->bplcon0 & BPC0_LACE) { | ||
3650 | cops = copdisplay.list[currentcop][0]; | ||
3651 | |||
3652 | (cops++)->l = CWAIT(0, 10); | ||
3653 | (cops++)->l = CMOVE(par->bplcon0, bplcon0); | ||
3654 | (cops++)->l = CMOVE(0, sprpt[0]); | ||
3655 | (cops++)->l = CMOVE2(0, sprpt[0]); | ||
3656 | |||
3657 | (copl++)->l = CMOVE(diwstrt2hw(par->diwstrt_h, par->diwstrt_v+1), diwstrt); | ||
3658 | (copl++)->l = CMOVE(diwstop2hw(par->diwstop_h, par->diwstop_v+1), diwstop); | ||
3659 | (cops++)->l = CMOVE(diwstrt2hw(par->diwstrt_h, par->diwstrt_v), diwstrt); | ||
3660 | (cops++)->l = CMOVE(diwstop2hw(par->diwstop_h, par->diwstop_v), diwstop); | ||
3661 | if (!IS_OCS) { | ||
3662 | (copl++)->l = CMOVE(diwhigh2hw(par->diwstrt_h, par->diwstrt_v+1, | ||
3663 | par->diwstop_h, par->diwstop_v+1), diwhigh); | ||
3664 | (cops++)->l = CMOVE(diwhigh2hw(par->diwstrt_h, par->diwstrt_v, | ||
3665 | par->diwstop_h, par->diwstop_v), diwhigh); | ||
3666 | #if 0 | ||
3667 | if (par->beamcon0 & BMC0_VARBEAMEN) { | ||
3668 | (copl++)->l = CMOVE(vtotal2hw(par->vtotal), vtotal); | ||
3669 | (copl++)->l = CMOVE(vbstrt2hw(par->vbstrt+1), vbstrt); | ||
3670 | (copl++)->l = CMOVE(vbstop2hw(par->vbstop+1), vbstop); | ||
3671 | (cops++)->l = CMOVE(vtotal2hw(par->vtotal), vtotal); | ||
3672 | (cops++)->l = CMOVE(vbstrt2hw(par->vbstrt), vbstrt); | ||
3673 | (cops++)->l = CMOVE(vbstop2hw(par->vbstop), vbstop); | ||
3674 | } | ||
3675 | #endif | ||
3676 | } | ||
3677 | p = ZTWO_PADDR(copdisplay.list[currentcop][0]); | ||
3678 | (copl++)->l = CMOVE(highw(p), cop2lc); | ||
3679 | (copl++)->l = CMOVE2(loww(p), cop2lc); | ||
3680 | p = ZTWO_PADDR(copdisplay.list[currentcop][1]); | ||
3681 | (cops++)->l = CMOVE(highw(p), cop2lc); | ||
3682 | (cops++)->l = CMOVE2(loww(p), cop2lc); | ||
3683 | copdisplay.rebuild[0] = cops; | ||
3684 | } else { | ||
3685 | (copl++)->l = CMOVE(diwstrt2hw(par->diwstrt_h, par->diwstrt_v), diwstrt); | ||
3686 | (copl++)->l = CMOVE(diwstop2hw(par->diwstop_h, par->diwstop_v), diwstop); | ||
3687 | if (!IS_OCS) { | ||
3688 | (copl++)->l = CMOVE(diwhigh2hw(par->diwstrt_h, par->diwstrt_v, | ||
3689 | par->diwstop_h, par->diwstop_v), diwhigh); | ||
3690 | #if 0 | ||
3691 | if (par->beamcon0 & BMC0_VARBEAMEN) { | ||
3692 | (copl++)->l = CMOVE(vtotal2hw(par->vtotal), vtotal); | ||
3693 | (copl++)->l = CMOVE(vbstrt2hw(par->vbstrt), vbstrt); | ||
3694 | (copl++)->l = CMOVE(vbstop2hw(par->vbstop), vbstop); | ||
3695 | } | ||
3696 | #endif | ||
3697 | } | ||
3698 | } | ||
3699 | copdisplay.rebuild[1] = copl; | ||
3700 | |||
3701 | ami_update_par(); | ||
3702 | ami_rebuild_copper(); | ||
3703 | } | ||
3704 | |||
3705 | /* | ||
3706 | * Rebuild the Copper List | ||
3707 | * | ||
3708 | * We only change the things that are not static | ||
3709 | */ | ||
3710 | |||
3711 | static void ami_rebuild_copper(void) | ||
3712 | { | ||
3713 | struct amifb_par *par = ¤tpar; | ||
3714 | copins *copl, *cops; | ||
3715 | u_short line, h_end1, h_end2; | ||
3716 | short i; | ||
3717 | u_long p; | ||
3718 | |||
3719 | if (IS_AGA && maxfmode + par->clk_shift == 0) | ||
3720 | h_end1 = par->diwstrt_h-64; | ||
3721 | else | ||
3722 | h_end1 = par->htotal-32; | ||
3723 | h_end2 = par->ddfstop+64; | ||
3724 | |||
3725 | ami_set_sprite(); | ||
3726 | |||
3727 | copl = copdisplay.rebuild[1]; | ||
3728 | p = par->bplpt0; | ||
3729 | if (par->vmode & FB_VMODE_YWRAP) { | ||
3730 | if ((par->vyres-par->yoffset) != 1 || !mod2(par->diwstrt_v)) { | ||
3731 | if (par->yoffset > par->vyres-par->yres) { | ||
3732 | for (i = 0; i < (short)par->bpp; i++, p += par->next_plane) { | ||
3733 | (copl++)->l = CMOVE(highw(p), bplpt[i]); | ||
3734 | (copl++)->l = CMOVE2(loww(p), bplpt[i]); | ||
3735 | } | ||
3736 | line = par->diwstrt_v + ((par->vyres-par->yoffset)<<par->line_shift) - 1; | ||
3737 | while (line >= 512) { | ||
3738 | (copl++)->l = CWAIT(h_end1, 510); | ||
3739 | line -= 512; | ||
3740 | } | ||
3741 | if (line >= 510 && IS_AGA && maxfmode + par->clk_shift == 0) | ||
3742 | (copl++)->l = CWAIT(h_end1, line); | ||
3743 | else | ||
3744 | (copl++)->l = CWAIT(h_end2, line); | ||
3745 | p = par->bplpt0wrap; | ||
3746 | } | ||
3747 | } else p = par->bplpt0wrap; | ||
3748 | } | ||
3749 | for (i = 0; i < (short)par->bpp; i++, p += par->next_plane) { | ||
3750 | (copl++)->l = CMOVE(highw(p), bplpt[i]); | ||
3751 | (copl++)->l = CMOVE2(loww(p), bplpt[i]); | ||
3752 | } | ||
3753 | copl->l = CEND; | ||
3754 | |||
3755 | if (par->bplcon0 & BPC0_LACE) { | ||
3756 | cops = copdisplay.rebuild[0]; | ||
3757 | p = par->bplpt0; | ||
3758 | if (mod2(par->diwstrt_v)) | ||
3759 | p -= par->next_line; | ||
3760 | else | ||
3761 | p += par->next_line; | ||
3762 | if (par->vmode & FB_VMODE_YWRAP) { | ||
3763 | if ((par->vyres-par->yoffset) != 1 || mod2(par->diwstrt_v)) { | ||
3764 | if (par->yoffset > par->vyres-par->yres+1) { | ||
3765 | for (i = 0; i < (short)par->bpp; i++, p += par->next_plane) { | ||
3766 | (cops++)->l = CMOVE(highw(p), bplpt[i]); | ||
3767 | (cops++)->l = CMOVE2(loww(p), bplpt[i]); | ||
3768 | } | ||
3769 | line = par->diwstrt_v + ((par->vyres-par->yoffset)<<par->line_shift) - 2; | ||
3770 | while (line >= 512) { | ||
3771 | (cops++)->l = CWAIT(h_end1, 510); | ||
3772 | line -= 512; | ||
3773 | } | ||
3774 | if (line > 510 && IS_AGA && maxfmode + par->clk_shift == 0) | ||
3775 | (cops++)->l = CWAIT(h_end1, line); | ||
3776 | else | ||
3777 | (cops++)->l = CWAIT(h_end2, line); | ||
3778 | p = par->bplpt0wrap; | ||
3779 | if (mod2(par->diwstrt_v+par->vyres-par->yoffset)) | ||
3780 | p -= par->next_line; | ||
3781 | else | ||
3782 | p += par->next_line; | ||
3783 | } | ||
3784 | } else p = par->bplpt0wrap - par->next_line; | ||
3785 | } | ||
3786 | for (i = 0; i < (short)par->bpp; i++, p += par->next_plane) { | ||
3787 | (cops++)->l = CMOVE(highw(p), bplpt[i]); | ||
3788 | (cops++)->l = CMOVE2(loww(p), bplpt[i]); | ||
3789 | } | ||
3790 | cops->l = CEND; | ||
3791 | } | ||
3792 | } | ||
3793 | 3768 | ||
3794 | static int __exit amifb_remove(struct platform_device *pdev) | 3769 | static int __exit amifb_remove(struct platform_device *pdev) |
3795 | { | 3770 | { |
3796 | unregister_framebuffer(&fb_info); | 3771 | struct fb_info *info = dev_get_drvdata(&pdev->dev); |
3797 | amifb_deinit(pdev); | 3772 | |
3773 | unregister_framebuffer(info); | ||
3774 | dev_set_drvdata(&pdev->dev, NULL); | ||
3775 | fb_dealloc_cmap(&info->cmap); | ||
3776 | free_irq(IRQ_AMIGA_COPPER, info->par); | ||
3777 | custom.dmacon = DMAF_ALL | DMAF_MASTER; | ||
3778 | if (videomemory) | ||
3779 | iounmap((void *)videomemory); | ||
3780 | chipfree(); | ||
3781 | framebuffer_release(info); | ||
3798 | amifb_video_off(); | 3782 | amifb_video_off(); |
3799 | return 0; | 3783 | return 0; |
3800 | } | 3784 | } |
diff --git a/drivers/video/atmel_lcdfb.c b/drivers/video/atmel_lcdfb.c index 63409c122ae8..0d7b20d4285d 100644 --- a/drivers/video/atmel_lcdfb.c +++ b/drivers/video/atmel_lcdfb.c | |||
@@ -100,8 +100,11 @@ static int atmel_bl_update_status(struct backlight_device *bl) | |||
100 | brightness = 0; | 100 | brightness = 0; |
101 | 101 | ||
102 | lcdc_writel(sinfo, ATMEL_LCDC_CONTRAST_VAL, brightness); | 102 | lcdc_writel(sinfo, ATMEL_LCDC_CONTRAST_VAL, brightness); |
103 | lcdc_writel(sinfo, ATMEL_LCDC_CONTRAST_CTR, | 103 | if (contrast_ctr & ATMEL_LCDC_POL_POSITIVE) |
104 | lcdc_writel(sinfo, ATMEL_LCDC_CONTRAST_CTR, | ||
104 | brightness ? contrast_ctr : 0); | 105 | brightness ? contrast_ctr : 0); |
106 | else | ||
107 | lcdc_writel(sinfo, ATMEL_LCDC_CONTRAST_CTR, contrast_ctr); | ||
105 | 108 | ||
106 | bl->props.fb_blank = bl->props.power = sinfo->bl_power = power; | 109 | bl->props.fb_blank = bl->props.power = sinfo->bl_power = power; |
107 | 110 | ||
@@ -682,14 +685,30 @@ static int atmel_lcdfb_setcolreg(unsigned int regno, unsigned int red, | |||
682 | 685 | ||
683 | case FB_VISUAL_PSEUDOCOLOR: | 686 | case FB_VISUAL_PSEUDOCOLOR: |
684 | if (regno < 256) { | 687 | if (regno < 256) { |
685 | val = ((red >> 11) & 0x001f); | 688 | if (cpu_is_at91sam9261() || cpu_is_at91sam9263() |
686 | val |= ((green >> 6) & 0x03e0); | 689 | || cpu_is_at91sam9rl()) { |
687 | val |= ((blue >> 1) & 0x7c00); | 690 | /* old style I+BGR:555 */ |
688 | 691 | val = ((red >> 11) & 0x001f); | |
689 | /* | 692 | val |= ((green >> 6) & 0x03e0); |
690 | * TODO: intensity bit. Maybe something like | 693 | val |= ((blue >> 1) & 0x7c00); |
691 | * ~(red[10] ^ green[10] ^ blue[10]) & 1 | 694 | |
692 | */ | 695 | /* |
696 | * TODO: intensity bit. Maybe something like | ||
697 | * ~(red[10] ^ green[10] ^ blue[10]) & 1 | ||
698 | */ | ||
699 | } else { | ||
700 | /* new style BGR:565 / RGB:565 */ | ||
701 | if (sinfo->lcd_wiring_mode == | ||
702 | ATMEL_LCDC_WIRING_RGB) { | ||
703 | val = ((blue >> 11) & 0x001f); | ||
704 | val |= ((red >> 0) & 0xf800); | ||
705 | } else { | ||
706 | val = ((red >> 11) & 0x001f); | ||
707 | val |= ((blue >> 0) & 0xf800); | ||
708 | } | ||
709 | |||
710 | val |= ((green >> 5) & 0x07e0); | ||
711 | } | ||
693 | 712 | ||
694 | lcdc_writel(sinfo, ATMEL_LCDC_LUT(regno), val); | 713 | lcdc_writel(sinfo, ATMEL_LCDC_LUT(regno), val); |
695 | ret = 0; | 714 | ret = 0; |
diff --git a/drivers/video/cirrusfb.c b/drivers/video/cirrusfb.c index 6fb499e7678f..738c8ce7d132 100644 --- a/drivers/video/cirrusfb.c +++ b/drivers/video/cirrusfb.c | |||
@@ -280,52 +280,74 @@ MODULE_DEVICE_TABLE(pci, cirrusfb_pci_table); | |||
280 | #endif /* CONFIG_PCI */ | 280 | #endif /* CONFIG_PCI */ |
281 | 281 | ||
282 | #ifdef CONFIG_ZORRO | 282 | #ifdef CONFIG_ZORRO |
283 | static const struct zorro_device_id cirrusfb_zorro_table[] = { | 283 | struct zorrocl { |
284 | enum cirrus_board type; /* Board type */ | ||
285 | u32 regoffset; /* Offset of registers in first Zorro device */ | ||
286 | u32 ramsize; /* Size of video RAM in first Zorro device */ | ||
287 | /* If zero, use autoprobe on RAM device */ | ||
288 | u32 ramoffset; /* Offset of video RAM in first Zorro device */ | ||
289 | zorro_id ramid; /* Zorro ID of RAM device */ | ||
290 | zorro_id ramid2; /* Zorro ID of optional second RAM device */ | ||
291 | }; | ||
292 | |||
293 | static const struct zorrocl zcl_sd64 __devinitconst = { | ||
294 | .type = BT_SD64, | ||
295 | .ramid = ZORRO_PROD_HELFRICH_SD64_RAM, | ||
296 | }; | ||
297 | |||
298 | static const struct zorrocl zcl_piccolo __devinitconst = { | ||
299 | .type = BT_PICCOLO, | ||
300 | .ramid = ZORRO_PROD_HELFRICH_PICCOLO_RAM, | ||
301 | }; | ||
302 | |||
303 | static const struct zorrocl zcl_picasso __devinitconst = { | ||
304 | .type = BT_PICASSO, | ||
305 | .ramid = ZORRO_PROD_VILLAGE_TRONIC_PICASSO_II_II_PLUS_RAM, | ||
306 | }; | ||
307 | |||
308 | static const struct zorrocl zcl_spectrum __devinitconst = { | ||
309 | .type = BT_SPECTRUM, | ||
310 | .ramid = ZORRO_PROD_GVP_EGS_28_24_SPECTRUM_RAM, | ||
311 | }; | ||
312 | |||
313 | static const struct zorrocl zcl_picasso4_z3 __devinitconst = { | ||
314 | .type = BT_PICASSO4, | ||
315 | .regoffset = 0x00600000, | ||
316 | .ramsize = 4 * MB_, | ||
317 | .ramoffset = 0x01000000, /* 0x02000000 for 64 MiB boards */ | ||
318 | }; | ||
319 | |||
320 | static const struct zorrocl zcl_picasso4_z2 __devinitconst = { | ||
321 | .type = BT_PICASSO4, | ||
322 | .regoffset = 0x10000, | ||
323 | .ramid = ZORRO_PROD_VILLAGE_TRONIC_PICASSO_IV_Z2_RAM1, | ||
324 | .ramid2 = ZORRO_PROD_VILLAGE_TRONIC_PICASSO_IV_Z2_RAM2, | ||
325 | }; | ||
326 | |||
327 | |||
328 | static const struct zorro_device_id cirrusfb_zorro_table[] __devinitconst = { | ||
284 | { | 329 | { |
285 | .id = ZORRO_PROD_HELFRICH_SD64_RAM, | 330 | .id = ZORRO_PROD_HELFRICH_SD64_REG, |
286 | .driver_data = BT_SD64, | 331 | .driver_data = (unsigned long)&zcl_sd64, |
287 | }, { | 332 | }, { |
288 | .id = ZORRO_PROD_HELFRICH_PICCOLO_RAM, | 333 | .id = ZORRO_PROD_HELFRICH_PICCOLO_REG, |
289 | .driver_data = BT_PICCOLO, | 334 | .driver_data = (unsigned long)&zcl_piccolo, |
290 | }, { | 335 | }, { |
291 | .id = ZORRO_PROD_VILLAGE_TRONIC_PICASSO_II_II_PLUS_RAM, | 336 | .id = ZORRO_PROD_VILLAGE_TRONIC_PICASSO_II_II_PLUS_REG, |
292 | .driver_data = BT_PICASSO, | 337 | .driver_data = (unsigned long)&zcl_picasso, |
293 | }, { | 338 | }, { |
294 | .id = ZORRO_PROD_GVP_EGS_28_24_SPECTRUM_RAM, | 339 | .id = ZORRO_PROD_GVP_EGS_28_24_SPECTRUM_REG, |
295 | .driver_data = BT_SPECTRUM, | 340 | .driver_data = (unsigned long)&zcl_spectrum, |
296 | }, { | 341 | }, { |
297 | .id = ZORRO_PROD_VILLAGE_TRONIC_PICASSO_IV_Z3, | 342 | .id = ZORRO_PROD_VILLAGE_TRONIC_PICASSO_IV_Z3, |
298 | .driver_data = BT_PICASSO4, | 343 | .driver_data = (unsigned long)&zcl_picasso4_z3, |
344 | }, { | ||
345 | .id = ZORRO_PROD_VILLAGE_TRONIC_PICASSO_IV_Z2_REG, | ||
346 | .driver_data = (unsigned long)&zcl_picasso4_z2, | ||
299 | }, | 347 | }, |
300 | { 0 } | 348 | { 0 } |
301 | }; | 349 | }; |
302 | MODULE_DEVICE_TABLE(zorro, cirrusfb_zorro_table); | 350 | MODULE_DEVICE_TABLE(zorro, cirrusfb_zorro_table); |
303 | |||
304 | static const struct { | ||
305 | zorro_id id2; | ||
306 | unsigned long size; | ||
307 | } cirrusfb_zorro_table2[] = { | ||
308 | [BT_SD64] = { | ||
309 | .id2 = ZORRO_PROD_HELFRICH_SD64_REG, | ||
310 | .size = 0x400000 | ||
311 | }, | ||
312 | [BT_PICCOLO] = { | ||
313 | .id2 = ZORRO_PROD_HELFRICH_PICCOLO_REG, | ||
314 | .size = 0x200000 | ||
315 | }, | ||
316 | [BT_PICASSO] = { | ||
317 | .id2 = ZORRO_PROD_VILLAGE_TRONIC_PICASSO_II_II_PLUS_REG, | ||
318 | .size = 0x200000 | ||
319 | }, | ||
320 | [BT_SPECTRUM] = { | ||
321 | .id2 = ZORRO_PROD_GVP_EGS_28_24_SPECTRUM_REG, | ||
322 | .size = 0x200000 | ||
323 | }, | ||
324 | [BT_PICASSO4] = { | ||
325 | .id2 = 0, | ||
326 | .size = 0x400000 | ||
327 | } | ||
328 | }; | ||
329 | #endif /* CONFIG_ZORRO */ | 351 | #endif /* CONFIG_ZORRO */ |
330 | 352 | ||
331 | #ifdef CIRRUSFB_DEBUG | 353 | #ifdef CIRRUSFB_DEBUG |
@@ -1956,16 +1978,12 @@ static void cirrusfb_zorro_unmap(struct fb_info *info) | |||
1956 | struct cirrusfb_info *cinfo = info->par; | 1978 | struct cirrusfb_info *cinfo = info->par; |
1957 | struct zorro_dev *zdev = to_zorro_dev(info->device); | 1979 | struct zorro_dev *zdev = to_zorro_dev(info->device); |
1958 | 1980 | ||
1959 | zorro_release_device(zdev); | 1981 | if (info->fix.smem_start > 16 * MB_) |
1960 | |||
1961 | if (cinfo->btype == BT_PICASSO4) { | ||
1962 | cinfo->regbase -= 0x600000; | ||
1963 | iounmap((void *)cinfo->regbase); | ||
1964 | iounmap(info->screen_base); | 1982 | iounmap(info->screen_base); |
1965 | } else { | 1983 | if (info->fix.mmio_start > 16 * MB_) |
1966 | if (zorro_resource_start(zdev) > 0x01000000) | 1984 | iounmap(cinfo->regbase); |
1967 | iounmap(info->screen_base); | 1985 | |
1968 | } | 1986 | zorro_release_device(zdev); |
1969 | } | 1987 | } |
1970 | #endif /* CONFIG_ZORRO */ | 1988 | #endif /* CONFIG_ZORRO */ |
1971 | 1989 | ||
@@ -2222,115 +2240,116 @@ static struct pci_driver cirrusfb_pci_driver = { | |||
2222 | static int __devinit cirrusfb_zorro_register(struct zorro_dev *z, | 2240 | static int __devinit cirrusfb_zorro_register(struct zorro_dev *z, |
2223 | const struct zorro_device_id *ent) | 2241 | const struct zorro_device_id *ent) |
2224 | { | 2242 | { |
2225 | struct cirrusfb_info *cinfo; | ||
2226 | struct fb_info *info; | 2243 | struct fb_info *info; |
2244 | int error; | ||
2245 | const struct zorrocl *zcl; | ||
2227 | enum cirrus_board btype; | 2246 | enum cirrus_board btype; |
2228 | struct zorro_dev *z2 = NULL; | 2247 | unsigned long regbase, ramsize, rambase; |
2229 | unsigned long board_addr, board_size, size; | 2248 | struct cirrusfb_info *cinfo; |
2230 | int ret; | ||
2231 | |||
2232 | btype = ent->driver_data; | ||
2233 | if (cirrusfb_zorro_table2[btype].id2) | ||
2234 | z2 = zorro_find_device(cirrusfb_zorro_table2[btype].id2, NULL); | ||
2235 | size = cirrusfb_zorro_table2[btype].size; | ||
2236 | 2249 | ||
2237 | info = framebuffer_alloc(sizeof(struct cirrusfb_info), &z->dev); | 2250 | info = framebuffer_alloc(sizeof(struct cirrusfb_info), &z->dev); |
2238 | if (!info) { | 2251 | if (!info) { |
2239 | printk(KERN_ERR "cirrusfb: could not allocate memory\n"); | 2252 | printk(KERN_ERR "cirrusfb: could not allocate memory\n"); |
2240 | ret = -ENOMEM; | 2253 | return -ENOMEM; |
2241 | goto err_out; | 2254 | } |
2255 | |||
2256 | zcl = (const struct zorrocl *)ent->driver_data; | ||
2257 | btype = zcl->type; | ||
2258 | regbase = zorro_resource_start(z) + zcl->regoffset; | ||
2259 | ramsize = zcl->ramsize; | ||
2260 | if (ramsize) { | ||
2261 | rambase = zorro_resource_start(z) + zcl->ramoffset; | ||
2262 | if (zorro_resource_len(z) == 64 * MB_) { | ||
2263 | /* Quirk for 64 MiB Picasso IV */ | ||
2264 | rambase += zcl->ramoffset; | ||
2265 | } | ||
2266 | } else { | ||
2267 | struct zorro_dev *ram = zorro_find_device(zcl->ramid, NULL); | ||
2268 | if (!ram || !zorro_resource_len(ram)) { | ||
2269 | dev_err(info->device, "No video RAM found\n"); | ||
2270 | error = -ENODEV; | ||
2271 | goto err_release_fb; | ||
2272 | } | ||
2273 | rambase = zorro_resource_start(ram); | ||
2274 | ramsize = zorro_resource_len(ram); | ||
2275 | if (zcl->ramid2 && | ||
2276 | (ram = zorro_find_device(zcl->ramid2, NULL))) { | ||
2277 | if (zorro_resource_start(ram) != rambase + ramsize) { | ||
2278 | dev_warn(info->device, | ||
2279 | "Skipping non-contiguous RAM at %pR\n", | ||
2280 | &ram->resource); | ||
2281 | } else { | ||
2282 | ramsize += zorro_resource_len(ram); | ||
2283 | } | ||
2284 | } | ||
2242 | } | 2285 | } |
2243 | 2286 | ||
2244 | dev_info(info->device, "%s board detected\n", | 2287 | dev_info(info->device, |
2245 | cirrusfb_board_info[btype].name); | 2288 | "%s board detected, REG at 0x%lx, %lu MiB RAM at 0x%lx\n", |
2246 | 2289 | cirrusfb_board_info[btype].name, regbase, ramsize / MB_, | |
2247 | cinfo = info->par; | 2290 | rambase); |
2248 | cinfo->btype = btype; | ||
2249 | |||
2250 | assert(z); | ||
2251 | assert(btype != BT_NONE); | ||
2252 | |||
2253 | board_addr = zorro_resource_start(z); | ||
2254 | board_size = zorro_resource_len(z); | ||
2255 | info->screen_size = size; | ||
2256 | 2291 | ||
2257 | if (!zorro_request_device(z, "cirrusfb")) { | 2292 | if (!zorro_request_device(z, "cirrusfb")) { |
2258 | dev_err(info->device, "cannot reserve region 0x%lx, abort\n", | 2293 | dev_err(info->device, "Cannot reserve %pR\n", &z->resource); |
2259 | board_addr); | 2294 | error = -EBUSY; |
2260 | ret = -EBUSY; | ||
2261 | goto err_release_fb; | 2295 | goto err_release_fb; |
2262 | } | 2296 | } |
2263 | 2297 | ||
2264 | ret = -EIO; | 2298 | cinfo = info->par; |
2265 | 2299 | cinfo->btype = btype; | |
2266 | if (btype == BT_PICASSO4) { | ||
2267 | dev_info(info->device, " REG at $%lx\n", board_addr + 0x600000); | ||
2268 | |||
2269 | /* To be precise, for the P4 this is not the */ | ||
2270 | /* begin of the board, but the begin of RAM. */ | ||
2271 | /* for P4, map in its address space in 2 chunks (### TEST! ) */ | ||
2272 | /* (note the ugly hardcoded 16M number) */ | ||
2273 | cinfo->regbase = ioremap(board_addr, 16777216); | ||
2274 | if (!cinfo->regbase) | ||
2275 | goto err_release_region; | ||
2276 | |||
2277 | dev_dbg(info->device, "Virtual address for board set to: $%p\n", | ||
2278 | cinfo->regbase); | ||
2279 | cinfo->regbase += 0x600000; | ||
2280 | info->fix.mmio_start = board_addr + 0x600000; | ||
2281 | |||
2282 | info->fix.smem_start = board_addr + 16777216; | ||
2283 | info->screen_base = ioremap(info->fix.smem_start, 16777216); | ||
2284 | if (!info->screen_base) | ||
2285 | goto err_unmap_regbase; | ||
2286 | } else { | ||
2287 | dev_info(info->device, " REG at $%lx\n", | ||
2288 | (unsigned long) z2->resource.start); | ||
2289 | |||
2290 | info->fix.smem_start = board_addr; | ||
2291 | if (board_addr > 0x01000000) | ||
2292 | info->screen_base = ioremap(board_addr, board_size); | ||
2293 | else | ||
2294 | info->screen_base = (caddr_t) ZTWO_VADDR(board_addr); | ||
2295 | if (!info->screen_base) | ||
2296 | goto err_release_region; | ||
2297 | 2300 | ||
2298 | /* set address for REG area of board */ | 2301 | info->fix.mmio_start = regbase; |
2299 | cinfo->regbase = (caddr_t) ZTWO_VADDR(z2->resource.start); | 2302 | cinfo->regbase = regbase > 16 * MB_ ? ioremap(regbase, 64 * 1024) |
2300 | info->fix.mmio_start = z2->resource.start; | 2303 | : (caddr_t)ZTWO_VADDR(regbase); |
2304 | if (!cinfo->regbase) { | ||
2305 | dev_err(info->device, "Cannot map registers\n"); | ||
2306 | error = -EIO; | ||
2307 | goto err_release_dev; | ||
2308 | } | ||
2301 | 2309 | ||
2302 | dev_dbg(info->device, "Virtual address for board set to: $%p\n", | 2310 | info->fix.smem_start = rambase; |
2303 | cinfo->regbase); | 2311 | info->screen_size = ramsize; |
2312 | info->screen_base = rambase > 16 * MB_ ? ioremap(rambase, ramsize) | ||
2313 | : (caddr_t)ZTWO_VADDR(rambase); | ||
2314 | if (!info->screen_base) { | ||
2315 | dev_err(info->device, "Cannot map video RAM\n"); | ||
2316 | error = -EIO; | ||
2317 | goto err_unmap_reg; | ||
2304 | } | 2318 | } |
2319 | |||
2305 | cinfo->unmap = cirrusfb_zorro_unmap; | 2320 | cinfo->unmap = cirrusfb_zorro_unmap; |
2306 | 2321 | ||
2307 | dev_info(info->device, | 2322 | dev_info(info->device, |
2308 | "Cirrus Logic chipset on Zorro bus, RAM (%lu MB) at $%lx\n", | 2323 | "Cirrus Logic chipset on Zorro bus, RAM (%lu MiB) at 0x%lx\n", |
2309 | board_size / MB_, board_addr); | 2324 | ramsize / MB_, rambase); |
2310 | |||
2311 | zorro_set_drvdata(z, info); | ||
2312 | 2325 | ||
2313 | /* MCLK select etc. */ | 2326 | /* MCLK select etc. */ |
2314 | if (cirrusfb_board_info[btype].init_sr1f) | 2327 | if (cirrusfb_board_info[btype].init_sr1f) |
2315 | vga_wseq(cinfo->regbase, CL_SEQR1F, | 2328 | vga_wseq(cinfo->regbase, CL_SEQR1F, |
2316 | cirrusfb_board_info[btype].sr1f); | 2329 | cirrusfb_board_info[btype].sr1f); |
2317 | 2330 | ||
2318 | ret = cirrusfb_register(info); | 2331 | error = cirrusfb_register(info); |
2319 | if (!ret) | 2332 | if (error) { |
2320 | return 0; | 2333 | dev_err(info->device, "Failed to register device, error %d\n", |
2334 | error); | ||
2335 | goto err_unmap_ram; | ||
2336 | } | ||
2321 | 2337 | ||
2322 | if (btype == BT_PICASSO4 || board_addr > 0x01000000) | 2338 | zorro_set_drvdata(z, info); |
2339 | return 0; | ||
2340 | |||
2341 | err_unmap_ram: | ||
2342 | if (rambase > 16 * MB_) | ||
2323 | iounmap(info->screen_base); | 2343 | iounmap(info->screen_base); |
2324 | 2344 | ||
2325 | err_unmap_regbase: | 2345 | err_unmap_reg: |
2326 | if (btype == BT_PICASSO4) | 2346 | if (regbase > 16 * MB_) |
2327 | iounmap(cinfo->regbase - 0x600000); | 2347 | iounmap(cinfo->regbase); |
2328 | err_release_region: | 2348 | err_release_dev: |
2329 | release_region(board_addr, board_size); | 2349 | zorro_release_device(z); |
2330 | err_release_fb: | 2350 | err_release_fb: |
2331 | framebuffer_release(info); | 2351 | framebuffer_release(info); |
2332 | err_out: | 2352 | return error; |
2333 | return ret; | ||
2334 | } | 2353 | } |
2335 | 2354 | ||
2336 | void __devexit cirrusfb_zorro_unregister(struct zorro_dev *z) | 2355 | void __devexit cirrusfb_zorro_unregister(struct zorro_dev *z) |
@@ -2338,6 +2357,7 @@ void __devexit cirrusfb_zorro_unregister(struct zorro_dev *z) | |||
2338 | struct fb_info *info = zorro_get_drvdata(z); | 2357 | struct fb_info *info = zorro_get_drvdata(z); |
2339 | 2358 | ||
2340 | cirrusfb_cleanup(info); | 2359 | cirrusfb_cleanup(info); |
2360 | zorro_set_drvdata(z, NULL); | ||
2341 | } | 2361 | } |
2342 | 2362 | ||
2343 | static struct zorro_driver cirrusfb_zorro_driver = { | 2363 | static struct zorro_driver cirrusfb_zorro_driver = { |
diff --git a/drivers/video/controlfb.c b/drivers/video/controlfb.c index 7b2c40abae15..0c189b32a4c5 100644 --- a/drivers/video/controlfb.c +++ b/drivers/video/controlfb.c | |||
@@ -420,7 +420,7 @@ static int __init init_control(struct fb_info_control *p) | |||
420 | 420 | ||
421 | /* Try to pick a video mode out of NVRAM if we have one. */ | 421 | /* Try to pick a video mode out of NVRAM if we have one. */ |
422 | #ifdef CONFIG_NVRAM | 422 | #ifdef CONFIG_NVRAM |
423 | if (default_cmode == CMODE_NVRAM){ | 423 | if (default_cmode == CMODE_NVRAM) { |
424 | cmode = nvram_read_byte(NV_CMODE); | 424 | cmode = nvram_read_byte(NV_CMODE); |
425 | if(cmode < CMODE_8 || cmode > CMODE_32) | 425 | if(cmode < CMODE_8 || cmode > CMODE_32) |
426 | cmode = CMODE_8; | 426 | cmode = CMODE_8; |
diff --git a/drivers/video/display/Kconfig b/drivers/video/display/Kconfig deleted file mode 100644 index f99af931d4f8..000000000000 --- a/drivers/video/display/Kconfig +++ /dev/null | |||
@@ -1,24 +0,0 @@ | |||
1 | # | ||
2 | # Display drivers configuration | ||
3 | # | ||
4 | |||
5 | menu "Display device support" | ||
6 | |||
7 | config DISPLAY_SUPPORT | ||
8 | tristate "Display panel/monitor support" | ||
9 | ---help--- | ||
10 | This framework adds support for low-level control of a display. | ||
11 | This includes support for power. | ||
12 | |||
13 | Enable this to be able to choose the drivers for controlling the | ||
14 | physical display panel/monitor on some platforms. This not only | ||
15 | covers LCD displays for PDAs but also other types of displays | ||
16 | such as CRT, TVout etc. | ||
17 | |||
18 | To have support for your specific display panel you will have to | ||
19 | select the proper drivers which depend on this option. | ||
20 | |||
21 | comment "Display hardware drivers" | ||
22 | depends on DISPLAY_SUPPORT | ||
23 | |||
24 | endmenu | ||
diff --git a/drivers/video/display/Makefile b/drivers/video/display/Makefile deleted file mode 100644 index c0ea832bf171..000000000000 --- a/drivers/video/display/Makefile +++ /dev/null | |||
@@ -1,6 +0,0 @@ | |||
1 | # Display drivers | ||
2 | |||
3 | display-objs := display-sysfs.o | ||
4 | |||
5 | obj-$(CONFIG_DISPLAY_SUPPORT) += display.o | ||
6 | |||
diff --git a/drivers/video/display/display-sysfs.c b/drivers/video/display/display-sysfs.c deleted file mode 100644 index 0c647d7af0ee..000000000000 --- a/drivers/video/display/display-sysfs.c +++ /dev/null | |||
@@ -1,219 +0,0 @@ | |||
1 | /* | ||
2 | * display-sysfs.c - Display output driver sysfs interface | ||
3 | * | ||
4 | * Copyright (C) 2007 James Simmons <jsimmons@infradead.org> | ||
5 | * | ||
6 | * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify | ||
9 | * it under the terms of the GNU General Public License as published by | ||
10 | * the Free Software Foundation; either version 2 of the License, or (at | ||
11 | * your option) any later version. | ||
12 | * | ||
13 | * This program is distributed in the hope that it will be useful, but | ||
14 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
16 | * General Public License for more details. | ||
17 | * | ||
18 | * You should have received a copy of the GNU General Public License along | ||
19 | * with this program; if not, write to the Free Software Foundation, Inc., | ||
20 | * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. | ||
21 | * | ||
22 | * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | ||
23 | */ | ||
24 | #include <linux/module.h> | ||
25 | #include <linux/display.h> | ||
26 | #include <linux/ctype.h> | ||
27 | #include <linux/idr.h> | ||
28 | #include <linux/err.h> | ||
29 | #include <linux/kdev_t.h> | ||
30 | #include <linux/slab.h> | ||
31 | |||
32 | static ssize_t display_show_name(struct device *dev, | ||
33 | struct device_attribute *attr, char *buf) | ||
34 | { | ||
35 | struct display_device *dsp = dev_get_drvdata(dev); | ||
36 | return snprintf(buf, PAGE_SIZE, "%s\n", dsp->name); | ||
37 | } | ||
38 | |||
39 | static ssize_t display_show_type(struct device *dev, | ||
40 | struct device_attribute *attr, char *buf) | ||
41 | { | ||
42 | struct display_device *dsp = dev_get_drvdata(dev); | ||
43 | return snprintf(buf, PAGE_SIZE, "%s\n", dsp->type); | ||
44 | } | ||
45 | |||
46 | static ssize_t display_show_contrast(struct device *dev, | ||
47 | struct device_attribute *attr, char *buf) | ||
48 | { | ||
49 | struct display_device *dsp = dev_get_drvdata(dev); | ||
50 | ssize_t rc = -ENXIO; | ||
51 | |||
52 | mutex_lock(&dsp->lock); | ||
53 | if (likely(dsp->driver) && dsp->driver->get_contrast) | ||
54 | rc = sprintf(buf, "%d\n", dsp->driver->get_contrast(dsp)); | ||
55 | mutex_unlock(&dsp->lock); | ||
56 | return rc; | ||
57 | } | ||
58 | |||
59 | static ssize_t display_store_contrast(struct device *dev, | ||
60 | struct device_attribute *attr, | ||
61 | const char *buf, size_t count) | ||
62 | { | ||
63 | struct display_device *dsp = dev_get_drvdata(dev); | ||
64 | ssize_t ret = -EINVAL, size; | ||
65 | int contrast; | ||
66 | char *endp; | ||
67 | |||
68 | contrast = simple_strtoul(buf, &endp, 0); | ||
69 | size = endp - buf; | ||
70 | |||
71 | if (isspace(*endp)) | ||
72 | size++; | ||
73 | |||
74 | if (size != count) | ||
75 | return ret; | ||
76 | |||
77 | mutex_lock(&dsp->lock); | ||
78 | if (likely(dsp->driver && dsp->driver->set_contrast)) { | ||
79 | pr_debug("display: set contrast to %d\n", contrast); | ||
80 | dsp->driver->set_contrast(dsp, contrast); | ||
81 | ret = count; | ||
82 | } | ||
83 | mutex_unlock(&dsp->lock); | ||
84 | return ret; | ||
85 | } | ||
86 | |||
87 | static ssize_t display_show_max_contrast(struct device *dev, | ||
88 | struct device_attribute *attr, | ||
89 | char *buf) | ||
90 | { | ||
91 | struct display_device *dsp = dev_get_drvdata(dev); | ||
92 | ssize_t rc = -ENXIO; | ||
93 | |||
94 | mutex_lock(&dsp->lock); | ||
95 | if (likely(dsp->driver)) | ||
96 | rc = sprintf(buf, "%d\n", dsp->driver->max_contrast); | ||
97 | mutex_unlock(&dsp->lock); | ||
98 | return rc; | ||
99 | } | ||
100 | |||
101 | static struct device_attribute display_attrs[] = { | ||
102 | __ATTR(name, S_IRUGO, display_show_name, NULL), | ||
103 | __ATTR(type, S_IRUGO, display_show_type, NULL), | ||
104 | __ATTR(contrast, S_IRUGO | S_IWUSR, display_show_contrast, display_store_contrast), | ||
105 | __ATTR(max_contrast, S_IRUGO, display_show_max_contrast, NULL), | ||
106 | }; | ||
107 | |||
108 | static int display_suspend(struct device *dev, pm_message_t state) | ||
109 | { | ||
110 | struct display_device *dsp = dev_get_drvdata(dev); | ||
111 | |||
112 | mutex_lock(&dsp->lock); | ||
113 | if (likely(dsp->driver->suspend)) | ||
114 | dsp->driver->suspend(dsp, state); | ||
115 | mutex_unlock(&dsp->lock); | ||
116 | return 0; | ||
117 | }; | ||
118 | |||
119 | static int display_resume(struct device *dev) | ||
120 | { | ||
121 | struct display_device *dsp = dev_get_drvdata(dev); | ||
122 | |||
123 | mutex_lock(&dsp->lock); | ||
124 | if (likely(dsp->driver->resume)) | ||
125 | dsp->driver->resume(dsp); | ||
126 | mutex_unlock(&dsp->lock); | ||
127 | return 0; | ||
128 | }; | ||
129 | |||
130 | static struct mutex allocated_dsp_lock; | ||
131 | static DEFINE_IDR(allocated_dsp); | ||
132 | static struct class *display_class; | ||
133 | |||
134 | struct display_device *display_device_register(struct display_driver *driver, | ||
135 | struct device *parent, void *devdata) | ||
136 | { | ||
137 | struct display_device *new_dev = NULL; | ||
138 | int ret = -EINVAL; | ||
139 | |||
140 | if (unlikely(!driver)) | ||
141 | return ERR_PTR(ret); | ||
142 | |||
143 | mutex_lock(&allocated_dsp_lock); | ||
144 | ret = idr_pre_get(&allocated_dsp, GFP_KERNEL); | ||
145 | mutex_unlock(&allocated_dsp_lock); | ||
146 | if (!ret) | ||
147 | return ERR_PTR(ret); | ||
148 | |||
149 | new_dev = kzalloc(sizeof(struct display_device), GFP_KERNEL); | ||
150 | if (likely(new_dev) && unlikely(driver->probe(new_dev, devdata))) { | ||
151 | // Reserve the index for this display | ||
152 | mutex_lock(&allocated_dsp_lock); | ||
153 | ret = idr_get_new(&allocated_dsp, new_dev, &new_dev->idx); | ||
154 | mutex_unlock(&allocated_dsp_lock); | ||
155 | |||
156 | if (!ret) { | ||
157 | new_dev->dev = device_create(display_class, parent, | ||
158 | MKDEV(0, 0), new_dev, | ||
159 | "display%d", new_dev->idx); | ||
160 | if (!IS_ERR(new_dev->dev)) { | ||
161 | new_dev->parent = parent; | ||
162 | new_dev->driver = driver; | ||
163 | mutex_init(&new_dev->lock); | ||
164 | return new_dev; | ||
165 | } | ||
166 | mutex_lock(&allocated_dsp_lock); | ||
167 | idr_remove(&allocated_dsp, new_dev->idx); | ||
168 | mutex_unlock(&allocated_dsp_lock); | ||
169 | ret = -EINVAL; | ||
170 | } | ||
171 | } | ||
172 | kfree(new_dev); | ||
173 | return ERR_PTR(ret); | ||
174 | } | ||
175 | EXPORT_SYMBOL(display_device_register); | ||
176 | |||
177 | void display_device_unregister(struct display_device *ddev) | ||
178 | { | ||
179 | if (!ddev) | ||
180 | return; | ||
181 | // Free device | ||
182 | mutex_lock(&ddev->lock); | ||
183 | device_unregister(ddev->dev); | ||
184 | mutex_unlock(&ddev->lock); | ||
185 | // Mark device index as available | ||
186 | mutex_lock(&allocated_dsp_lock); | ||
187 | idr_remove(&allocated_dsp, ddev->idx); | ||
188 | mutex_unlock(&allocated_dsp_lock); | ||
189 | kfree(ddev); | ||
190 | } | ||
191 | EXPORT_SYMBOL(display_device_unregister); | ||
192 | |||
193 | static int __init display_class_init(void) | ||
194 | { | ||
195 | display_class = class_create(THIS_MODULE, "display"); | ||
196 | if (IS_ERR(display_class)) { | ||
197 | printk(KERN_ERR "Failed to create display class\n"); | ||
198 | display_class = NULL; | ||
199 | return -EINVAL; | ||
200 | } | ||
201 | display_class->dev_attrs = display_attrs; | ||
202 | display_class->suspend = display_suspend; | ||
203 | display_class->resume = display_resume; | ||
204 | mutex_init(&allocated_dsp_lock); | ||
205 | return 0; | ||
206 | } | ||
207 | |||
208 | static void __exit display_class_exit(void) | ||
209 | { | ||
210 | class_destroy(display_class); | ||
211 | } | ||
212 | |||
213 | module_init(display_class_init); | ||
214 | module_exit(display_class_exit); | ||
215 | |||
216 | MODULE_DESCRIPTION("Display Hardware handling"); | ||
217 | MODULE_AUTHOR("James Simmons <jsimmons@infradead.org>"); | ||
218 | MODULE_LICENSE("GPL"); | ||
219 | |||
diff --git a/drivers/video/fbmem.c b/drivers/video/fbmem.c index ad936295d8f4..ac9141b85356 100644 --- a/drivers/video/fbmem.c +++ b/drivers/video/fbmem.c | |||
@@ -967,6 +967,20 @@ fb_set_var(struct fb_info *info, struct fb_var_screeninfo *var) | |||
967 | memcmp(&info->var, var, sizeof(struct fb_var_screeninfo))) { | 967 | memcmp(&info->var, var, sizeof(struct fb_var_screeninfo))) { |
968 | u32 activate = var->activate; | 968 | u32 activate = var->activate; |
969 | 969 | ||
970 | /* When using FOURCC mode, make sure the red, green, blue and | ||
971 | * transp fields are set to 0. | ||
972 | */ | ||
973 | if ((info->fix.capabilities & FB_CAP_FOURCC) && | ||
974 | var->grayscale > 1) { | ||
975 | if (var->red.offset || var->green.offset || | ||
976 | var->blue.offset || var->transp.offset || | ||
977 | var->red.length || var->green.length || | ||
978 | var->blue.length || var->transp.length || | ||
979 | var->red.msb_right || var->green.msb_right || | ||
980 | var->blue.msb_right || var->transp.msb_right) | ||
981 | return -EINVAL; | ||
982 | } | ||
983 | |||
970 | if (!info->fbops->fb_check_var) { | 984 | if (!info->fbops->fb_check_var) { |
971 | *var = info->var; | 985 | *var = info->var; |
972 | goto done; | 986 | goto done; |
diff --git a/drivers/video/fsl-diu-fb.c b/drivers/video/fsl-diu-fb.c index a16beeb5f548..acf292bfba02 100644 --- a/drivers/video/fsl-diu-fb.c +++ b/drivers/video/fsl-diu-fb.c | |||
@@ -36,8 +36,7 @@ | |||
36 | #include <linux/fsl-diu-fb.h> | 36 | #include <linux/fsl-diu-fb.h> |
37 | #include "edid.h" | 37 | #include "edid.h" |
38 | 38 | ||
39 | #define FSL_AOI_NUM 6 /* 5 AOIs and one dummy AOI */ | 39 | #define NUM_AOIS 5 /* 1 for plane 0, 2 for planes 1 & 2 each */ |
40 | /* 1 for plane 0, 2 for plane 1&2 each */ | ||
41 | 40 | ||
42 | /* HW cursor parameters */ | 41 | /* HW cursor parameters */ |
43 | #define MAX_CURS 32 | 42 | #define MAX_CURS 32 |
@@ -49,12 +48,6 @@ | |||
49 | #define INT_PARERR 0x08 /* Display parameters error interrupt */ | 48 | #define INT_PARERR 0x08 /* Display parameters error interrupt */ |
50 | #define INT_LS_BF_VS 0x10 /* Lines before vsync. interrupt */ | 49 | #define INT_LS_BF_VS 0x10 /* Lines before vsync. interrupt */ |
51 | 50 | ||
52 | struct diu_addr { | ||
53 | void *vaddr; /* Virtual address */ | ||
54 | dma_addr_t paddr; /* Physical address */ | ||
55 | __u32 offset; | ||
56 | }; | ||
57 | |||
58 | /* | 51 | /* |
59 | * List of supported video modes | 52 | * List of supported video modes |
60 | * | 53 | * |
@@ -330,23 +323,6 @@ static unsigned int d_cache_line_size; | |||
330 | 323 | ||
331 | static DEFINE_SPINLOCK(diu_lock); | 324 | static DEFINE_SPINLOCK(diu_lock); |
332 | 325 | ||
333 | struct fsl_diu_data { | ||
334 | struct fb_info *fsl_diu_info[FSL_AOI_NUM - 1]; | ||
335 | /*FSL_AOI_NUM has one dummy AOI */ | ||
336 | struct device_attribute dev_attr; | ||
337 | struct diu_ad *dummy_ad; | ||
338 | void *dummy_aoi_virt; | ||
339 | unsigned int irq; | ||
340 | int fb_enabled; | ||
341 | enum fsl_diu_monitor_port monitor_port; | ||
342 | struct diu __iomem *diu_reg; | ||
343 | spinlock_t reg_lock; | ||
344 | struct diu_addr ad; | ||
345 | struct diu_addr gamma; | ||
346 | struct diu_addr pallete; | ||
347 | struct diu_addr cursor; | ||
348 | }; | ||
349 | |||
350 | enum mfb_index { | 326 | enum mfb_index { |
351 | PLANE0 = 0, /* Plane 0, only one AOI that fills the screen */ | 327 | PLANE0 = 0, /* Plane 0, only one AOI that fills the screen */ |
352 | PLANE1_AOI0, /* Plane 1, first AOI */ | 328 | PLANE1_AOI0, /* Plane 1, first AOI */ |
@@ -370,6 +346,42 @@ struct mfb_info { | |||
370 | u8 *edid_data; | 346 | u8 *edid_data; |
371 | }; | 347 | }; |
372 | 348 | ||
349 | /** | ||
350 | * struct fsl_diu_data - per-DIU data structure | ||
351 | * @dma_addr: DMA address of this structure | ||
352 | * @fsl_diu_info: fb_info objects, one per AOI | ||
353 | * @dev_attr: sysfs structure | ||
354 | * @irq: IRQ | ||
355 | * @monitor_port: the monitor port this DIU is connected to | ||
356 | * @diu_reg: pointer to the DIU hardware registers | ||
357 | * @reg_lock: spinlock for register access | ||
358 | * @dummy_aoi: video buffer for the 4x4 32-bit dummy AOI | ||
359 | * dummy_ad: DIU Area Descriptor for the dummy AOI | ||
360 | * @ad[]: Area Descriptors for each real AOI | ||
361 | * @gamma: gamma color table | ||
362 | * @cursor: hardware cursor data | ||
363 | * | ||
364 | * This data structure must be allocated with 32-byte alignment, so that the | ||
365 | * internal fields can be aligned properly. | ||
366 | */ | ||
367 | struct fsl_diu_data { | ||
368 | dma_addr_t dma_addr; | ||
369 | struct fb_info fsl_diu_info[NUM_AOIS]; | ||
370 | struct mfb_info mfb[NUM_AOIS]; | ||
371 | struct device_attribute dev_attr; | ||
372 | unsigned int irq; | ||
373 | enum fsl_diu_monitor_port monitor_port; | ||
374 | struct diu __iomem *diu_reg; | ||
375 | spinlock_t reg_lock; | ||
376 | u8 dummy_aoi[4 * 4 * 4]; | ||
377 | struct diu_ad dummy_ad __aligned(8); | ||
378 | struct diu_ad ad[NUM_AOIS] __aligned(8); | ||
379 | u8 gamma[256 * 3] __aligned(32); | ||
380 | u8 cursor[MAX_CURS * MAX_CURS * 2] __aligned(32); | ||
381 | } __aligned(32); | ||
382 | |||
383 | /* Determine the DMA address of a member of the fsl_diu_data structure */ | ||
384 | #define DMA_ADDR(p, f) ((p)->dma_addr + offsetof(struct fsl_diu_data, f)) | ||
373 | 385 | ||
374 | static struct mfb_info mfb_template[] = { | 386 | static struct mfb_info mfb_template[] = { |
375 | { | 387 | { |
@@ -449,37 +461,6 @@ static enum fsl_diu_monitor_port fsl_diu_name_to_port(const char *s) | |||
449 | return diu_ops.valid_monitor_port(port); | 461 | return diu_ops.valid_monitor_port(port); |
450 | } | 462 | } |
451 | 463 | ||
452 | /** | ||
453 | * fsl_diu_alloc - allocate memory for the DIU | ||
454 | * @size: number of bytes to allocate | ||
455 | * @param: returned physical address of memory | ||
456 | * | ||
457 | * This function allocates a physically-contiguous block of memory. | ||
458 | */ | ||
459 | static void *fsl_diu_alloc(size_t size, phys_addr_t *phys) | ||
460 | { | ||
461 | void *virt; | ||
462 | |||
463 | virt = alloc_pages_exact(size, GFP_DMA | __GFP_ZERO); | ||
464 | if (virt) | ||
465 | *phys = virt_to_phys(virt); | ||
466 | |||
467 | return virt; | ||
468 | } | ||
469 | |||
470 | /** | ||
471 | * fsl_diu_free - release DIU memory | ||
472 | * @virt: pointer returned by fsl_diu_alloc() | ||
473 | * @size: number of bytes allocated by fsl_diu_alloc() | ||
474 | * | ||
475 | * This function releases memory allocated by fsl_diu_alloc(). | ||
476 | */ | ||
477 | static void fsl_diu_free(void *virt, size_t size) | ||
478 | { | ||
479 | if (virt && size) | ||
480 | free_pages_exact(virt, size); | ||
481 | } | ||
482 | |||
483 | /* | 464 | /* |
484 | * Workaround for failed writing desc register of planes. | 465 | * Workaround for failed writing desc register of planes. |
485 | * Needed with MPC5121 DIU rev 2.0 silicon. | 466 | * Needed with MPC5121 DIU rev 2.0 silicon. |
@@ -495,8 +476,8 @@ static void fsl_diu_enable_panel(struct fb_info *info) | |||
495 | { | 476 | { |
496 | struct mfb_info *pmfbi, *cmfbi, *mfbi = info->par; | 477 | struct mfb_info *pmfbi, *cmfbi, *mfbi = info->par; |
497 | struct diu_ad *ad = mfbi->ad; | 478 | struct diu_ad *ad = mfbi->ad; |
498 | struct fsl_diu_data *machine_data = mfbi->parent; | 479 | struct fsl_diu_data *data = mfbi->parent; |
499 | struct diu __iomem *hw = machine_data->diu_reg; | 480 | struct diu __iomem *hw = data->diu_reg; |
500 | 481 | ||
501 | switch (mfbi->index) { | 482 | switch (mfbi->index) { |
502 | case PLANE0: | 483 | case PLANE0: |
@@ -504,7 +485,7 @@ static void fsl_diu_enable_panel(struct fb_info *info) | |||
504 | wr_reg_wa(&hw->desc[0], ad->paddr); | 485 | wr_reg_wa(&hw->desc[0], ad->paddr); |
505 | break; | 486 | break; |
506 | case PLANE1_AOI0: | 487 | case PLANE1_AOI0: |
507 | cmfbi = machine_data->fsl_diu_info[2]->par; | 488 | cmfbi = &data->mfb[2]; |
508 | if (hw->desc[1] != ad->paddr) { /* AOI0 closed */ | 489 | if (hw->desc[1] != ad->paddr) { /* AOI0 closed */ |
509 | if (cmfbi->count > 0) /* AOI1 open */ | 490 | if (cmfbi->count > 0) /* AOI1 open */ |
510 | ad->next_ad = | 491 | ad->next_ad = |
@@ -515,7 +496,7 @@ static void fsl_diu_enable_panel(struct fb_info *info) | |||
515 | } | 496 | } |
516 | break; | 497 | break; |
517 | case PLANE2_AOI0: | 498 | case PLANE2_AOI0: |
518 | cmfbi = machine_data->fsl_diu_info[4]->par; | 499 | cmfbi = &data->mfb[4]; |
519 | if (hw->desc[2] != ad->paddr) { /* AOI0 closed */ | 500 | if (hw->desc[2] != ad->paddr) { /* AOI0 closed */ |
520 | if (cmfbi->count > 0) /* AOI1 open */ | 501 | if (cmfbi->count > 0) /* AOI1 open */ |
521 | ad->next_ad = | 502 | ad->next_ad = |
@@ -526,17 +507,17 @@ static void fsl_diu_enable_panel(struct fb_info *info) | |||
526 | } | 507 | } |
527 | break; | 508 | break; |
528 | case PLANE1_AOI1: | 509 | case PLANE1_AOI1: |
529 | pmfbi = machine_data->fsl_diu_info[1]->par; | 510 | pmfbi = &data->mfb[1]; |
530 | ad->next_ad = 0; | 511 | ad->next_ad = 0; |
531 | if (hw->desc[1] == machine_data->dummy_ad->paddr) | 512 | if (hw->desc[1] == data->dummy_ad.paddr) |
532 | wr_reg_wa(&hw->desc[1], ad->paddr); | 513 | wr_reg_wa(&hw->desc[1], ad->paddr); |
533 | else /* AOI0 open */ | 514 | else /* AOI0 open */ |
534 | pmfbi->ad->next_ad = cpu_to_le32(ad->paddr); | 515 | pmfbi->ad->next_ad = cpu_to_le32(ad->paddr); |
535 | break; | 516 | break; |
536 | case PLANE2_AOI1: | 517 | case PLANE2_AOI1: |
537 | pmfbi = machine_data->fsl_diu_info[3]->par; | 518 | pmfbi = &data->mfb[3]; |
538 | ad->next_ad = 0; | 519 | ad->next_ad = 0; |
539 | if (hw->desc[2] == machine_data->dummy_ad->paddr) | 520 | if (hw->desc[2] == data->dummy_ad.paddr) |
540 | wr_reg_wa(&hw->desc[2], ad->paddr); | 521 | wr_reg_wa(&hw->desc[2], ad->paddr); |
541 | else /* AOI0 was open */ | 522 | else /* AOI0 was open */ |
542 | pmfbi->ad->next_ad = cpu_to_le32(ad->paddr); | 523 | pmfbi->ad->next_ad = cpu_to_le32(ad->paddr); |
@@ -548,52 +529,52 @@ static void fsl_diu_disable_panel(struct fb_info *info) | |||
548 | { | 529 | { |
549 | struct mfb_info *pmfbi, *cmfbi, *mfbi = info->par; | 530 | struct mfb_info *pmfbi, *cmfbi, *mfbi = info->par; |
550 | struct diu_ad *ad = mfbi->ad; | 531 | struct diu_ad *ad = mfbi->ad; |
551 | struct fsl_diu_data *machine_data = mfbi->parent; | 532 | struct fsl_diu_data *data = mfbi->parent; |
552 | struct diu __iomem *hw = machine_data->diu_reg; | 533 | struct diu __iomem *hw = data->diu_reg; |
553 | 534 | ||
554 | switch (mfbi->index) { | 535 | switch (mfbi->index) { |
555 | case PLANE0: | 536 | case PLANE0: |
556 | if (hw->desc[0] != machine_data->dummy_ad->paddr) | 537 | if (hw->desc[0] != data->dummy_ad.paddr) |
557 | wr_reg_wa(&hw->desc[0], machine_data->dummy_ad->paddr); | 538 | wr_reg_wa(&hw->desc[0], data->dummy_ad.paddr); |
558 | break; | 539 | break; |
559 | case PLANE1_AOI0: | 540 | case PLANE1_AOI0: |
560 | cmfbi = machine_data->fsl_diu_info[2]->par; | 541 | cmfbi = &data->mfb[2]; |
561 | if (cmfbi->count > 0) /* AOI1 is open */ | 542 | if (cmfbi->count > 0) /* AOI1 is open */ |
562 | wr_reg_wa(&hw->desc[1], cmfbi->ad->paddr); | 543 | wr_reg_wa(&hw->desc[1], cmfbi->ad->paddr); |
563 | /* move AOI1 to the first */ | 544 | /* move AOI1 to the first */ |
564 | else /* AOI1 was closed */ | 545 | else /* AOI1 was closed */ |
565 | wr_reg_wa(&hw->desc[1], machine_data->dummy_ad->paddr); | 546 | wr_reg_wa(&hw->desc[1], data->dummy_ad.paddr); |
566 | /* close AOI 0 */ | 547 | /* close AOI 0 */ |
567 | break; | 548 | break; |
568 | case PLANE2_AOI0: | 549 | case PLANE2_AOI0: |
569 | cmfbi = machine_data->fsl_diu_info[4]->par; | 550 | cmfbi = &data->mfb[4]; |
570 | if (cmfbi->count > 0) /* AOI1 is open */ | 551 | if (cmfbi->count > 0) /* AOI1 is open */ |
571 | wr_reg_wa(&hw->desc[2], cmfbi->ad->paddr); | 552 | wr_reg_wa(&hw->desc[2], cmfbi->ad->paddr); |
572 | /* move AOI1 to the first */ | 553 | /* move AOI1 to the first */ |
573 | else /* AOI1 was closed */ | 554 | else /* AOI1 was closed */ |
574 | wr_reg_wa(&hw->desc[2], machine_data->dummy_ad->paddr); | 555 | wr_reg_wa(&hw->desc[2], data->dummy_ad.paddr); |
575 | /* close AOI 0 */ | 556 | /* close AOI 0 */ |
576 | break; | 557 | break; |
577 | case PLANE1_AOI1: | 558 | case PLANE1_AOI1: |
578 | pmfbi = machine_data->fsl_diu_info[1]->par; | 559 | pmfbi = &data->mfb[1]; |
579 | if (hw->desc[1] != ad->paddr) { | 560 | if (hw->desc[1] != ad->paddr) { |
580 | /* AOI1 is not the first in the chain */ | 561 | /* AOI1 is not the first in the chain */ |
581 | if (pmfbi->count > 0) | 562 | if (pmfbi->count > 0) |
582 | /* AOI0 is open, must be the first */ | 563 | /* AOI0 is open, must be the first */ |
583 | pmfbi->ad->next_ad = 0; | 564 | pmfbi->ad->next_ad = 0; |
584 | } else /* AOI1 is the first in the chain */ | 565 | } else /* AOI1 is the first in the chain */ |
585 | wr_reg_wa(&hw->desc[1], machine_data->dummy_ad->paddr); | 566 | wr_reg_wa(&hw->desc[1], data->dummy_ad.paddr); |
586 | /* close AOI 1 */ | 567 | /* close AOI 1 */ |
587 | break; | 568 | break; |
588 | case PLANE2_AOI1: | 569 | case PLANE2_AOI1: |
589 | pmfbi = machine_data->fsl_diu_info[3]->par; | 570 | pmfbi = &data->mfb[3]; |
590 | if (hw->desc[2] != ad->paddr) { | 571 | if (hw->desc[2] != ad->paddr) { |
591 | /* AOI1 is not the first in the chain */ | 572 | /* AOI1 is not the first in the chain */ |
592 | if (pmfbi->count > 0) | 573 | if (pmfbi->count > 0) |
593 | /* AOI0 is open, must be the first */ | 574 | /* AOI0 is open, must be the first */ |
594 | pmfbi->ad->next_ad = 0; | 575 | pmfbi->ad->next_ad = 0; |
595 | } else /* AOI1 is the first in the chain */ | 576 | } else /* AOI1 is the first in the chain */ |
596 | wr_reg_wa(&hw->desc[2], machine_data->dummy_ad->paddr); | 577 | wr_reg_wa(&hw->desc[2], data->dummy_ad.paddr); |
597 | /* close AOI 1 */ | 578 | /* close AOI 1 */ |
598 | break; | 579 | break; |
599 | } | 580 | } |
@@ -602,39 +583,33 @@ static void fsl_diu_disable_panel(struct fb_info *info) | |||
602 | static void enable_lcdc(struct fb_info *info) | 583 | static void enable_lcdc(struct fb_info *info) |
603 | { | 584 | { |
604 | struct mfb_info *mfbi = info->par; | 585 | struct mfb_info *mfbi = info->par; |
605 | struct fsl_diu_data *machine_data = mfbi->parent; | 586 | struct fsl_diu_data *data = mfbi->parent; |
606 | struct diu __iomem *hw = machine_data->diu_reg; | 587 | struct diu __iomem *hw = data->diu_reg; |
607 | 588 | ||
608 | if (!machine_data->fb_enabled) { | 589 | out_be32(&hw->diu_mode, MFB_MODE1); |
609 | out_be32(&hw->diu_mode, MFB_MODE1); | ||
610 | machine_data->fb_enabled++; | ||
611 | } | ||
612 | } | 590 | } |
613 | 591 | ||
614 | static void disable_lcdc(struct fb_info *info) | 592 | static void disable_lcdc(struct fb_info *info) |
615 | { | 593 | { |
616 | struct mfb_info *mfbi = info->par; | 594 | struct mfb_info *mfbi = info->par; |
617 | struct fsl_diu_data *machine_data = mfbi->parent; | 595 | struct fsl_diu_data *data = mfbi->parent; |
618 | struct diu __iomem *hw = machine_data->diu_reg; | 596 | struct diu __iomem *hw = data->diu_reg; |
619 | 597 | ||
620 | if (machine_data->fb_enabled) { | 598 | out_be32(&hw->diu_mode, 0); |
621 | out_be32(&hw->diu_mode, 0); | ||
622 | machine_data->fb_enabled = 0; | ||
623 | } | ||
624 | } | 599 | } |
625 | 600 | ||
626 | static void adjust_aoi_size_position(struct fb_var_screeninfo *var, | 601 | static void adjust_aoi_size_position(struct fb_var_screeninfo *var, |
627 | struct fb_info *info) | 602 | struct fb_info *info) |
628 | { | 603 | { |
629 | struct mfb_info *lower_aoi_mfbi, *upper_aoi_mfbi, *mfbi = info->par; | 604 | struct mfb_info *lower_aoi_mfbi, *upper_aoi_mfbi, *mfbi = info->par; |
630 | struct fsl_diu_data *machine_data = mfbi->parent; | 605 | struct fsl_diu_data *data = mfbi->parent; |
631 | int available_height, upper_aoi_bottom; | 606 | int available_height, upper_aoi_bottom; |
632 | enum mfb_index index = mfbi->index; | 607 | enum mfb_index index = mfbi->index; |
633 | int lower_aoi_is_open, upper_aoi_is_open; | 608 | int lower_aoi_is_open, upper_aoi_is_open; |
634 | __u32 base_plane_width, base_plane_height, upper_aoi_height; | 609 | __u32 base_plane_width, base_plane_height, upper_aoi_height; |
635 | 610 | ||
636 | base_plane_width = machine_data->fsl_diu_info[0]->var.xres; | 611 | base_plane_width = data->fsl_diu_info[0].var.xres; |
637 | base_plane_height = machine_data->fsl_diu_info[0]->var.yres; | 612 | base_plane_height = data->fsl_diu_info[0].var.yres; |
638 | 613 | ||
639 | if (mfbi->x_aoi_d < 0) | 614 | if (mfbi->x_aoi_d < 0) |
640 | mfbi->x_aoi_d = 0; | 615 | mfbi->x_aoi_d = 0; |
@@ -649,7 +624,7 @@ static void adjust_aoi_size_position(struct fb_var_screeninfo *var, | |||
649 | break; | 624 | break; |
650 | case PLANE1_AOI0: | 625 | case PLANE1_AOI0: |
651 | case PLANE2_AOI0: | 626 | case PLANE2_AOI0: |
652 | lower_aoi_mfbi = machine_data->fsl_diu_info[index+1]->par; | 627 | lower_aoi_mfbi = data->fsl_diu_info[index+1].par; |
653 | lower_aoi_is_open = lower_aoi_mfbi->count > 0 ? 1 : 0; | 628 | lower_aoi_is_open = lower_aoi_mfbi->count > 0 ? 1 : 0; |
654 | if (var->xres > base_plane_width) | 629 | if (var->xres > base_plane_width) |
655 | var->xres = base_plane_width; | 630 | var->xres = base_plane_width; |
@@ -667,9 +642,8 @@ static void adjust_aoi_size_position(struct fb_var_screeninfo *var, | |||
667 | break; | 642 | break; |
668 | case PLANE1_AOI1: | 643 | case PLANE1_AOI1: |
669 | case PLANE2_AOI1: | 644 | case PLANE2_AOI1: |
670 | upper_aoi_mfbi = machine_data->fsl_diu_info[index-1]->par; | 645 | upper_aoi_mfbi = data->fsl_diu_info[index-1].par; |
671 | upper_aoi_height = | 646 | upper_aoi_height = data->fsl_diu_info[index-1].var.yres; |
672 | machine_data->fsl_diu_info[index-1]->var.yres; | ||
673 | upper_aoi_bottom = upper_aoi_mfbi->y_aoi_d + upper_aoi_height; | 647 | upper_aoi_bottom = upper_aoi_mfbi->y_aoi_d + upper_aoi_height; |
674 | upper_aoi_is_open = upper_aoi_mfbi->count > 0 ? 1 : 0; | 648 | upper_aoi_is_open = upper_aoi_mfbi->count > 0 ? 1 : 0; |
675 | if (var->xres > base_plane_width) | 649 | if (var->xres > base_plane_width) |
@@ -809,33 +783,33 @@ static void update_lcdc(struct fb_info *info) | |||
809 | { | 783 | { |
810 | struct fb_var_screeninfo *var = &info->var; | 784 | struct fb_var_screeninfo *var = &info->var; |
811 | struct mfb_info *mfbi = info->par; | 785 | struct mfb_info *mfbi = info->par; |
812 | struct fsl_diu_data *machine_data = mfbi->parent; | 786 | struct fsl_diu_data *data = mfbi->parent; |
813 | struct diu __iomem *hw; | 787 | struct diu __iomem *hw; |
814 | int i, j; | 788 | int i, j; |
815 | char __iomem *cursor_base, *gamma_table_base; | 789 | u8 *gamma_table_base; |
816 | 790 | ||
817 | u32 temp; | 791 | u32 temp; |
818 | 792 | ||
819 | hw = machine_data->diu_reg; | 793 | hw = data->diu_reg; |
794 | |||
795 | diu_ops.set_monitor_port(data->monitor_port); | ||
796 | gamma_table_base = data->gamma; | ||
820 | 797 | ||
821 | diu_ops.set_monitor_port(machine_data->monitor_port); | ||
822 | gamma_table_base = machine_data->gamma.vaddr; | ||
823 | cursor_base = machine_data->cursor.vaddr; | ||
824 | /* Prep for DIU init - gamma table, cursor table */ | 798 | /* Prep for DIU init - gamma table, cursor table */ |
825 | 799 | ||
826 | for (i = 0; i <= 2; i++) | 800 | for (i = 0; i <= 2; i++) |
827 | for (j = 0; j <= 255; j++) | 801 | for (j = 0; j <= 255; j++) |
828 | *gamma_table_base++ = j; | 802 | *gamma_table_base++ = j; |
829 | 803 | ||
830 | diu_ops.set_gamma_table(machine_data->monitor_port, | 804 | if (diu_ops.set_gamma_table) |
831 | machine_data->gamma.vaddr); | 805 | diu_ops.set_gamma_table(data->monitor_port, data->gamma); |
832 | 806 | ||
833 | disable_lcdc(info); | 807 | disable_lcdc(info); |
834 | 808 | ||
835 | /* Program DIU registers */ | 809 | /* Program DIU registers */ |
836 | 810 | ||
837 | out_be32(&hw->gamma, machine_data->gamma.paddr); | 811 | out_be32(&hw->gamma, DMA_ADDR(data, gamma)); |
838 | out_be32(&hw->cursor, machine_data->cursor.paddr); | 812 | out_be32(&hw->cursor, DMA_ADDR(data, cursor)); |
839 | 813 | ||
840 | out_be32(&hw->bgnd, 0x007F7F7F); /* BGND */ | 814 | out_be32(&hw->bgnd, 0x007F7F7F); /* BGND */ |
841 | out_be32(&hw->bgnd_wb, 0); /* BGND_WB */ | 815 | out_be32(&hw->bgnd_wb, 0); /* BGND_WB */ |
@@ -870,16 +844,17 @@ static void update_lcdc(struct fb_info *info) | |||
870 | 844 | ||
871 | static int map_video_memory(struct fb_info *info) | 845 | static int map_video_memory(struct fb_info *info) |
872 | { | 846 | { |
873 | phys_addr_t phys; | ||
874 | u32 smem_len = info->fix.line_length * info->var.yres_virtual; | 847 | u32 smem_len = info->fix.line_length * info->var.yres_virtual; |
848 | void *p; | ||
875 | 849 | ||
876 | info->screen_base = fsl_diu_alloc(smem_len, &phys); | 850 | p = alloc_pages_exact(smem_len, GFP_DMA | __GFP_ZERO); |
877 | if (info->screen_base == NULL) { | 851 | if (!p) { |
878 | dev_err(info->dev, "unable to allocate fb memory\n"); | 852 | dev_err(info->dev, "unable to allocate fb memory\n"); |
879 | return -ENOMEM; | 853 | return -ENOMEM; |
880 | } | 854 | } |
881 | mutex_lock(&info->mm_lock); | 855 | mutex_lock(&info->mm_lock); |
882 | info->fix.smem_start = (unsigned long) phys; | 856 | info->screen_base = p; |
857 | info->fix.smem_start = virt_to_phys(info->screen_base); | ||
883 | info->fix.smem_len = smem_len; | 858 | info->fix.smem_len = smem_len; |
884 | mutex_unlock(&info->mm_lock); | 859 | mutex_unlock(&info->mm_lock); |
885 | info->screen_size = info->fix.smem_len; | 860 | info->screen_size = info->fix.smem_len; |
@@ -889,12 +864,17 @@ static int map_video_memory(struct fb_info *info) | |||
889 | 864 | ||
890 | static void unmap_video_memory(struct fb_info *info) | 865 | static void unmap_video_memory(struct fb_info *info) |
891 | { | 866 | { |
892 | fsl_diu_free(info->screen_base, info->fix.smem_len); | 867 | void *p = info->screen_base; |
868 | size_t l = info->fix.smem_len; | ||
869 | |||
893 | mutex_lock(&info->mm_lock); | 870 | mutex_lock(&info->mm_lock); |
894 | info->screen_base = NULL; | 871 | info->screen_base = NULL; |
895 | info->fix.smem_start = 0; | 872 | info->fix.smem_start = 0; |
896 | info->fix.smem_len = 0; | 873 | info->fix.smem_len = 0; |
897 | mutex_unlock(&info->mm_lock); | 874 | mutex_unlock(&info->mm_lock); |
875 | |||
876 | if (p) | ||
877 | free_pages_exact(p, l); | ||
898 | } | 878 | } |
899 | 879 | ||
900 | /* | 880 | /* |
@@ -913,6 +893,59 @@ static int fsl_diu_set_aoi(struct fb_info *info) | |||
913 | return 0; | 893 | return 0; |
914 | } | 894 | } |
915 | 895 | ||
896 | /** | ||
897 | * fsl_diu_get_pixel_format: return the pixel format for a given color depth | ||
898 | * | ||
899 | * The pixel format is a 32-bit value that determine which bits in each | ||
900 | * pixel are to be used for each color. This is the default function used | ||
901 | * if the platform does not define its own version. | ||
902 | */ | ||
903 | static u32 fsl_diu_get_pixel_format(unsigned int bits_per_pixel) | ||
904 | { | ||
905 | #define PF_BYTE_F 0x10000000 | ||
906 | #define PF_ALPHA_C_MASK 0x0E000000 | ||
907 | #define PF_ALPHA_C_SHIFT 25 | ||
908 | #define PF_BLUE_C_MASK 0x01800000 | ||
909 | #define PF_BLUE_C_SHIFT 23 | ||
910 | #define PF_GREEN_C_MASK 0x00600000 | ||
911 | #define PF_GREEN_C_SHIFT 21 | ||
912 | #define PF_RED_C_MASK 0x00180000 | ||
913 | #define PF_RED_C_SHIFT 19 | ||
914 | #define PF_PALETTE 0x00040000 | ||
915 | #define PF_PIXEL_S_MASK 0x00030000 | ||
916 | #define PF_PIXEL_S_SHIFT 16 | ||
917 | #define PF_COMP_3_MASK 0x0000F000 | ||
918 | #define PF_COMP_3_SHIFT 12 | ||
919 | #define PF_COMP_2_MASK 0x00000F00 | ||
920 | #define PF_COMP_2_SHIFT 8 | ||
921 | #define PF_COMP_1_MASK 0x000000F0 | ||
922 | #define PF_COMP_1_SHIFT 4 | ||
923 | #define PF_COMP_0_MASK 0x0000000F | ||
924 | #define PF_COMP_0_SHIFT 0 | ||
925 | |||
926 | #define MAKE_PF(alpha, red, blue, green, size, c0, c1, c2, c3) \ | ||
927 | cpu_to_le32(PF_BYTE_F | (alpha << PF_ALPHA_C_SHIFT) | \ | ||
928 | (blue << PF_BLUE_C_SHIFT) | (green << PF_GREEN_C_SHIFT) | \ | ||
929 | (red << PF_RED_C_SHIFT) | (c3 << PF_COMP_3_SHIFT) | \ | ||
930 | (c2 << PF_COMP_2_SHIFT) | (c1 << PF_COMP_1_SHIFT) | \ | ||
931 | (c0 << PF_COMP_0_SHIFT) | (size << PF_PIXEL_S_SHIFT)) | ||
932 | |||
933 | switch (bits_per_pixel) { | ||
934 | case 32: | ||
935 | /* 0x88883316 */ | ||
936 | return MAKE_PF(3, 2, 0, 1, 3, 8, 8, 8, 8); | ||
937 | case 24: | ||
938 | /* 0x88082219 */ | ||
939 | return MAKE_PF(4, 0, 1, 2, 2, 0, 8, 8, 8); | ||
940 | case 16: | ||
941 | /* 0x65053118 */ | ||
942 | return MAKE_PF(4, 2, 1, 0, 1, 5, 6, 5, 0); | ||
943 | default: | ||
944 | pr_err("fsl-diu: unsupported color depth %u\n", bits_per_pixel); | ||
945 | return 0; | ||
946 | } | ||
947 | } | ||
948 | |||
916 | /* | 949 | /* |
917 | * Using the fb_var_screeninfo in fb_info we set the resolution of this | 950 | * Using the fb_var_screeninfo in fb_info we set the resolution of this |
918 | * particular framebuffer. This function alters the fb_fix_screeninfo stored | 951 | * particular framebuffer. This function alters the fb_fix_screeninfo stored |
@@ -926,11 +959,11 @@ static int fsl_diu_set_par(struct fb_info *info) | |||
926 | unsigned long len; | 959 | unsigned long len; |
927 | struct fb_var_screeninfo *var = &info->var; | 960 | struct fb_var_screeninfo *var = &info->var; |
928 | struct mfb_info *mfbi = info->par; | 961 | struct mfb_info *mfbi = info->par; |
929 | struct fsl_diu_data *machine_data = mfbi->parent; | 962 | struct fsl_diu_data *data = mfbi->parent; |
930 | struct diu_ad *ad = mfbi->ad; | 963 | struct diu_ad *ad = mfbi->ad; |
931 | struct diu __iomem *hw; | 964 | struct diu __iomem *hw; |
932 | 965 | ||
933 | hw = machine_data->diu_reg; | 966 | hw = data->diu_reg; |
934 | 967 | ||
935 | set_fix(info); | 968 | set_fix(info); |
936 | mfbi->cursor_reset = 1; | 969 | mfbi->cursor_reset = 1; |
@@ -948,8 +981,12 @@ static int fsl_diu_set_par(struct fb_info *info) | |||
948 | } | 981 | } |
949 | } | 982 | } |
950 | 983 | ||
951 | ad->pix_fmt = diu_ops.get_pixel_format(machine_data->monitor_port, | 984 | if (diu_ops.get_pixel_format) |
952 | var->bits_per_pixel); | 985 | ad->pix_fmt = diu_ops.get_pixel_format(data->monitor_port, |
986 | var->bits_per_pixel); | ||
987 | else | ||
988 | ad->pix_fmt = fsl_diu_get_pixel_format(var->bits_per_pixel); | ||
989 | |||
953 | ad->addr = cpu_to_le32(info->fix.smem_start); | 990 | ad->addr = cpu_to_le32(info->fix.smem_start); |
954 | ad->src_size_g_alpha = cpu_to_le32((var->yres_virtual << 12) | | 991 | ad->src_size_g_alpha = cpu_to_le32((var->yres_virtual << 12) | |
955 | var->xres_virtual) | mfbi->g_alpha; | 992 | var->xres_virtual) | mfbi->g_alpha; |
@@ -1208,21 +1245,6 @@ static struct fb_ops fsl_diu_ops = { | |||
1208 | .fb_release = fsl_diu_release, | 1245 | .fb_release = fsl_diu_release, |
1209 | }; | 1246 | }; |
1210 | 1247 | ||
1211 | static int init_fbinfo(struct fb_info *info) | ||
1212 | { | ||
1213 | struct mfb_info *mfbi = info->par; | ||
1214 | |||
1215 | info->device = NULL; | ||
1216 | info->var.activate = FB_ACTIVATE_NOW; | ||
1217 | info->fbops = &fsl_diu_ops; | ||
1218 | info->flags = FBINFO_FLAG_DEFAULT; | ||
1219 | info->pseudo_palette = &mfbi->pseudo_palette; | ||
1220 | |||
1221 | /* Allocate colormap */ | ||
1222 | fb_alloc_cmap(&info->cmap, 16, 0); | ||
1223 | return 0; | ||
1224 | } | ||
1225 | |||
1226 | static int __devinit install_fb(struct fb_info *info) | 1248 | static int __devinit install_fb(struct fb_info *info) |
1227 | { | 1249 | { |
1228 | int rc; | 1250 | int rc; |
@@ -1232,8 +1254,15 @@ static int __devinit install_fb(struct fb_info *info) | |||
1232 | unsigned int dbsize = ARRAY_SIZE(fsl_diu_mode_db); | 1254 | unsigned int dbsize = ARRAY_SIZE(fsl_diu_mode_db); |
1233 | int has_default_mode = 1; | 1255 | int has_default_mode = 1; |
1234 | 1256 | ||
1235 | if (init_fbinfo(info)) | 1257 | info->var.activate = FB_ACTIVATE_NOW; |
1236 | return -EINVAL; | 1258 | info->fbops = &fsl_diu_ops; |
1259 | info->flags = FBINFO_DEFAULT | FBINFO_VIRTFB | FBINFO_PARTIAL_PAN_OK | | ||
1260 | FBINFO_READS_FAST; | ||
1261 | info->pseudo_palette = mfbi->pseudo_palette; | ||
1262 | |||
1263 | rc = fb_alloc_cmap(&info->cmap, 16, 0); | ||
1264 | if (rc) | ||
1265 | return rc; | ||
1237 | 1266 | ||
1238 | if (mfbi->index == PLANE0) { | 1267 | if (mfbi->index == PLANE0) { |
1239 | if (mfbi->edid_data) { | 1268 | if (mfbi->edid_data) { |
@@ -1359,16 +1388,16 @@ static irqreturn_t fsl_diu_isr(int irq, void *dev_id) | |||
1359 | return IRQ_NONE; | 1388 | return IRQ_NONE; |
1360 | } | 1389 | } |
1361 | 1390 | ||
1362 | static int request_irq_local(struct fsl_diu_data *machine_data) | 1391 | static int request_irq_local(struct fsl_diu_data *data) |
1363 | { | 1392 | { |
1364 | struct diu __iomem *hw = machine_data->diu_reg; | 1393 | struct diu __iomem *hw = data->diu_reg; |
1365 | u32 ints; | 1394 | u32 ints; |
1366 | int ret; | 1395 | int ret; |
1367 | 1396 | ||
1368 | /* Read to clear the status */ | 1397 | /* Read to clear the status */ |
1369 | in_be32(&hw->int_status); | 1398 | in_be32(&hw->int_status); |
1370 | 1399 | ||
1371 | ret = request_irq(machine_data->irq, fsl_diu_isr, 0, "fsl-diu-fb", hw); | 1400 | ret = request_irq(data->irq, fsl_diu_isr, 0, "fsl-diu-fb", hw); |
1372 | if (!ret) { | 1401 | if (!ret) { |
1373 | ints = INT_PARERR | INT_LS_BF_VS; | 1402 | ints = INT_PARERR | INT_LS_BF_VS; |
1374 | #if !defined(CONFIG_NOT_COHERENT_CACHE) | 1403 | #if !defined(CONFIG_NOT_COHERENT_CACHE) |
@@ -1383,14 +1412,14 @@ static int request_irq_local(struct fsl_diu_data *machine_data) | |||
1383 | return ret; | 1412 | return ret; |
1384 | } | 1413 | } |
1385 | 1414 | ||
1386 | static void free_irq_local(struct fsl_diu_data *machine_data) | 1415 | static void free_irq_local(struct fsl_diu_data *data) |
1387 | { | 1416 | { |
1388 | struct diu __iomem *hw = machine_data->diu_reg; | 1417 | struct diu __iomem *hw = data->diu_reg; |
1389 | 1418 | ||
1390 | /* Disable all LCDC interrupt */ | 1419 | /* Disable all LCDC interrupt */ |
1391 | out_be32(&hw->int_mask, 0x1f); | 1420 | out_be32(&hw->int_mask, 0x1f); |
1392 | 1421 | ||
1393 | free_irq(machine_data->irq, NULL); | 1422 | free_irq(data->irq, NULL); |
1394 | } | 1423 | } |
1395 | 1424 | ||
1396 | #ifdef CONFIG_PM | 1425 | #ifdef CONFIG_PM |
@@ -1400,20 +1429,20 @@ static void free_irq_local(struct fsl_diu_data *machine_data) | |||
1400 | */ | 1429 | */ |
1401 | static int fsl_diu_suspend(struct platform_device *ofdev, pm_message_t state) | 1430 | static int fsl_diu_suspend(struct platform_device *ofdev, pm_message_t state) |
1402 | { | 1431 | { |
1403 | struct fsl_diu_data *machine_data; | 1432 | struct fsl_diu_data *data; |
1404 | 1433 | ||
1405 | machine_data = dev_get_drvdata(&ofdev->dev); | 1434 | data = dev_get_drvdata(&ofdev->dev); |
1406 | disable_lcdc(machine_data->fsl_diu_info[0]); | 1435 | disable_lcdc(data->fsl_diu_info[0]); |
1407 | 1436 | ||
1408 | return 0; | 1437 | return 0; |
1409 | } | 1438 | } |
1410 | 1439 | ||
1411 | static int fsl_diu_resume(struct platform_device *ofdev) | 1440 | static int fsl_diu_resume(struct platform_device *ofdev) |
1412 | { | 1441 | { |
1413 | struct fsl_diu_data *machine_data; | 1442 | struct fsl_diu_data *data; |
1414 | 1443 | ||
1415 | machine_data = dev_get_drvdata(&ofdev->dev); | 1444 | data = dev_get_drvdata(&ofdev->dev); |
1416 | enable_lcdc(machine_data->fsl_diu_info[0]); | 1445 | enable_lcdc(data->fsl_diu_info[0]); |
1417 | 1446 | ||
1418 | return 0; | 1447 | return 0; |
1419 | } | 1448 | } |
@@ -1423,56 +1452,24 @@ static int fsl_diu_resume(struct platform_device *ofdev) | |||
1423 | #define fsl_diu_resume NULL | 1452 | #define fsl_diu_resume NULL |
1424 | #endif /* CONFIG_PM */ | 1453 | #endif /* CONFIG_PM */ |
1425 | 1454 | ||
1426 | /* Align to 64-bit(8-byte), 32-byte, etc. */ | ||
1427 | static int allocate_buf(struct device *dev, struct diu_addr *buf, u32 size, | ||
1428 | u32 bytes_align) | ||
1429 | { | ||
1430 | u32 offset; | ||
1431 | dma_addr_t mask; | ||
1432 | |||
1433 | buf->vaddr = | ||
1434 | dma_alloc_coherent(dev, size + bytes_align, &buf->paddr, | ||
1435 | GFP_DMA | __GFP_ZERO); | ||
1436 | if (!buf->vaddr) | ||
1437 | return -ENOMEM; | ||
1438 | |||
1439 | mask = bytes_align - 1; | ||
1440 | offset = buf->paddr & mask; | ||
1441 | if (offset) { | ||
1442 | buf->offset = bytes_align - offset; | ||
1443 | buf->paddr = buf->paddr + offset; | ||
1444 | } else | ||
1445 | buf->offset = 0; | ||
1446 | |||
1447 | return 0; | ||
1448 | } | ||
1449 | |||
1450 | static void free_buf(struct device *dev, struct diu_addr *buf, u32 size, | ||
1451 | u32 bytes_align) | ||
1452 | { | ||
1453 | dma_free_coherent(dev, size + bytes_align, buf->vaddr, | ||
1454 | buf->paddr - buf->offset); | ||
1455 | } | ||
1456 | |||
1457 | static ssize_t store_monitor(struct device *device, | 1455 | static ssize_t store_monitor(struct device *device, |
1458 | struct device_attribute *attr, const char *buf, size_t count) | 1456 | struct device_attribute *attr, const char *buf, size_t count) |
1459 | { | 1457 | { |
1460 | enum fsl_diu_monitor_port old_monitor_port; | 1458 | enum fsl_diu_monitor_port old_monitor_port; |
1461 | struct fsl_diu_data *machine_data = | 1459 | struct fsl_diu_data *data = |
1462 | container_of(attr, struct fsl_diu_data, dev_attr); | 1460 | container_of(attr, struct fsl_diu_data, dev_attr); |
1463 | 1461 | ||
1464 | old_monitor_port = machine_data->monitor_port; | 1462 | old_monitor_port = data->monitor_port; |
1465 | machine_data->monitor_port = fsl_diu_name_to_port(buf); | 1463 | data->monitor_port = fsl_diu_name_to_port(buf); |
1466 | 1464 | ||
1467 | if (old_monitor_port != machine_data->monitor_port) { | 1465 | if (old_monitor_port != data->monitor_port) { |
1468 | /* All AOIs need adjust pixel format | 1466 | /* All AOIs need adjust pixel format |
1469 | * fsl_diu_set_par only change the pixsel format here | 1467 | * fsl_diu_set_par only change the pixsel format here |
1470 | * unlikely to fail. */ | 1468 | * unlikely to fail. */ |
1471 | fsl_diu_set_par(machine_data->fsl_diu_info[0]); | 1469 | unsigned int i; |
1472 | fsl_diu_set_par(machine_data->fsl_diu_info[1]); | 1470 | |
1473 | fsl_diu_set_par(machine_data->fsl_diu_info[2]); | 1471 | for (i=0; i < NUM_AOIS; i++) |
1474 | fsl_diu_set_par(machine_data->fsl_diu_info[3]); | 1472 | fsl_diu_set_par(&data->fsl_diu_info[i]); |
1475 | fsl_diu_set_par(machine_data->fsl_diu_info[4]); | ||
1476 | } | 1473 | } |
1477 | return count; | 1474 | return count; |
1478 | } | 1475 | } |
@@ -1480,10 +1477,10 @@ static ssize_t store_monitor(struct device *device, | |||
1480 | static ssize_t show_monitor(struct device *device, | 1477 | static ssize_t show_monitor(struct device *device, |
1481 | struct device_attribute *attr, char *buf) | 1478 | struct device_attribute *attr, char *buf) |
1482 | { | 1479 | { |
1483 | struct fsl_diu_data *machine_data = | 1480 | struct fsl_diu_data *data = |
1484 | container_of(attr, struct fsl_diu_data, dev_attr); | 1481 | container_of(attr, struct fsl_diu_data, dev_attr); |
1485 | 1482 | ||
1486 | switch (machine_data->monitor_port) { | 1483 | switch (data->monitor_port) { |
1487 | case FSL_DIU_PORT_DVI: | 1484 | case FSL_DIU_PORT_DVI: |
1488 | return sprintf(buf, "DVI\n"); | 1485 | return sprintf(buf, "DVI\n"); |
1489 | case FSL_DIU_PORT_LVDS: | 1486 | case FSL_DIU_PORT_LVDS: |
@@ -1499,28 +1496,52 @@ static int __devinit fsl_diu_probe(struct platform_device *pdev) | |||
1499 | { | 1496 | { |
1500 | struct device_node *np = pdev->dev.of_node; | 1497 | struct device_node *np = pdev->dev.of_node; |
1501 | struct mfb_info *mfbi; | 1498 | struct mfb_info *mfbi; |
1502 | phys_addr_t dummy_ad_addr = 0; | 1499 | struct fsl_diu_data *data; |
1503 | int ret, i, error = 0; | ||
1504 | struct fsl_diu_data *machine_data; | ||
1505 | int diu_mode; | 1500 | int diu_mode; |
1501 | dma_addr_t dma_addr; /* DMA addr of fsl_diu_data struct */ | ||
1502 | unsigned int i; | ||
1503 | int ret; | ||
1506 | 1504 | ||
1507 | machine_data = kzalloc(sizeof(struct fsl_diu_data), GFP_KERNEL); | 1505 | data = dma_alloc_coherent(&pdev->dev, sizeof(struct fsl_diu_data), |
1508 | if (!machine_data) | 1506 | &dma_addr, GFP_DMA | __GFP_ZERO); |
1507 | if (!data) | ||
1509 | return -ENOMEM; | 1508 | return -ENOMEM; |
1509 | data->dma_addr = dma_addr; | ||
1510 | |||
1511 | /* | ||
1512 | * dma_alloc_coherent() uses a page allocator, so the address is | ||
1513 | * always page-aligned. We need the memory to be 32-byte aligned, | ||
1514 | * so that's good. However, if one day the allocator changes, we | ||
1515 | * need to catch that. It's not worth the effort to handle unaligned | ||
1516 | * alloctions now because it's highly unlikely to ever be a problem. | ||
1517 | */ | ||
1518 | if ((unsigned long)data & 31) { | ||
1519 | dev_err(&pdev->dev, "misaligned allocation"); | ||
1520 | ret = -ENOMEM; | ||
1521 | goto error; | ||
1522 | } | ||
1510 | 1523 | ||
1511 | spin_lock_init(&machine_data->reg_lock); | 1524 | spin_lock_init(&data->reg_lock); |
1512 | 1525 | ||
1513 | for (i = 0; i < ARRAY_SIZE(machine_data->fsl_diu_info); i++) { | 1526 | for (i = 0; i < NUM_AOIS; i++) { |
1514 | machine_data->fsl_diu_info[i] = | 1527 | struct fb_info *info = &data->fsl_diu_info[i]; |
1515 | framebuffer_alloc(sizeof(struct mfb_info), &pdev->dev); | 1528 | |
1516 | if (!machine_data->fsl_diu_info[i]) { | 1529 | info->device = &pdev->dev; |
1517 | dev_err(&pdev->dev, "cannot allocate memory\n"); | 1530 | info->par = &data->mfb[i]; |
1518 | ret = -ENOMEM; | 1531 | |
1519 | goto error2; | 1532 | /* |
1520 | } | 1533 | * We store the physical address of the AD in the reserved |
1521 | mfbi = machine_data->fsl_diu_info[i]->par; | 1534 | * 'paddr' field of the AD itself. |
1535 | */ | ||
1536 | data->ad[i].paddr = DMA_ADDR(data, ad[i]); | ||
1537 | |||
1538 | info->fix.smem_start = 0; | ||
1539 | |||
1540 | /* Initialize the AOI data structure */ | ||
1541 | mfbi = info->par; | ||
1522 | memcpy(mfbi, &mfb_template[i], sizeof(struct mfb_info)); | 1542 | memcpy(mfbi, &mfb_template[i], sizeof(struct mfb_info)); |
1523 | mfbi->parent = machine_data; | 1543 | mfbi->parent = data; |
1544 | mfbi->ad = &data->ad[i]; | ||
1524 | 1545 | ||
1525 | if (mfbi->index == PLANE0) { | 1546 | if (mfbi->index == PLANE0) { |
1526 | const u8 *prop; | 1547 | const u8 *prop; |
@@ -1534,158 +1555,102 @@ static int __devinit fsl_diu_probe(struct platform_device *pdev) | |||
1534 | } | 1555 | } |
1535 | } | 1556 | } |
1536 | 1557 | ||
1537 | machine_data->diu_reg = of_iomap(np, 0); | 1558 | data->diu_reg = of_iomap(np, 0); |
1538 | if (!machine_data->diu_reg) { | 1559 | if (!data->diu_reg) { |
1539 | dev_err(&pdev->dev, "cannot map DIU registers\n"); | 1560 | dev_err(&pdev->dev, "cannot map DIU registers\n"); |
1540 | ret = -EFAULT; | 1561 | ret = -EFAULT; |
1541 | goto error2; | 1562 | goto error; |
1542 | } | 1563 | } |
1543 | 1564 | ||
1544 | diu_mode = in_be32(&machine_data->diu_reg->diu_mode); | 1565 | diu_mode = in_be32(&data->diu_reg->diu_mode); |
1545 | if (diu_mode == MFB_MODE0) | 1566 | if (diu_mode == MFB_MODE0) |
1546 | out_be32(&machine_data->diu_reg->diu_mode, 0); /* disable DIU */ | 1567 | out_be32(&data->diu_reg->diu_mode, 0); /* disable DIU */ |
1547 | 1568 | ||
1548 | /* Get the IRQ of the DIU */ | 1569 | /* Get the IRQ of the DIU */ |
1549 | machine_data->irq = irq_of_parse_and_map(np, 0); | 1570 | data->irq = irq_of_parse_and_map(np, 0); |
1550 | 1571 | ||
1551 | if (!machine_data->irq) { | 1572 | if (!data->irq) { |
1552 | dev_err(&pdev->dev, "could not get DIU IRQ\n"); | 1573 | dev_err(&pdev->dev, "could not get DIU IRQ\n"); |
1553 | ret = -EINVAL; | 1574 | ret = -EINVAL; |
1554 | goto error; | 1575 | goto error; |
1555 | } | 1576 | } |
1556 | machine_data->monitor_port = monitor_port; | 1577 | data->monitor_port = monitor_port; |
1557 | 1578 | ||
1558 | /* Area descriptor memory pool aligns to 64-bit boundary */ | 1579 | /* Initialize the dummy Area Descriptor */ |
1559 | if (allocate_buf(&pdev->dev, &machine_data->ad, | 1580 | data->dummy_ad.addr = cpu_to_le32(DMA_ADDR(data, dummy_aoi)); |
1560 | sizeof(struct diu_ad) * FSL_AOI_NUM, 8)) | 1581 | data->dummy_ad.pix_fmt = 0x88882317; |
1561 | return -ENOMEM; | 1582 | data->dummy_ad.src_size_g_alpha = cpu_to_le32((4 << 12) | 4); |
1562 | 1583 | data->dummy_ad.aoi_size = cpu_to_le32((4 << 16) | 2); | |
1563 | /* Get memory for Gamma Table - 32-byte aligned memory */ | 1584 | data->dummy_ad.offset_xyi = 0; |
1564 | if (allocate_buf(&pdev->dev, &machine_data->gamma, 768, 32)) { | 1585 | data->dummy_ad.offset_xyd = 0; |
1565 | ret = -ENOMEM; | 1586 | data->dummy_ad.next_ad = 0; |
1566 | goto error; | 1587 | data->dummy_ad.paddr = DMA_ADDR(data, dummy_ad); |
1567 | } | ||
1568 | |||
1569 | /* For performance, cursor bitmap buffer aligns to 32-byte boundary */ | ||
1570 | if (allocate_buf(&pdev->dev, &machine_data->cursor, | ||
1571 | MAX_CURS * MAX_CURS * 2, 32)) { | ||
1572 | ret = -ENOMEM; | ||
1573 | goto error; | ||
1574 | } | ||
1575 | |||
1576 | i = ARRAY_SIZE(machine_data->fsl_diu_info); | ||
1577 | machine_data->dummy_ad = (struct diu_ad *)((u32)machine_data->ad.vaddr + | ||
1578 | machine_data->ad.offset) + i; | ||
1579 | machine_data->dummy_ad->paddr = machine_data->ad.paddr + | ||
1580 | i * sizeof(struct diu_ad); | ||
1581 | machine_data->dummy_aoi_virt = fsl_diu_alloc(64, &dummy_ad_addr); | ||
1582 | if (!machine_data->dummy_aoi_virt) { | ||
1583 | ret = -ENOMEM; | ||
1584 | goto error; | ||
1585 | } | ||
1586 | machine_data->dummy_ad->addr = cpu_to_le32(dummy_ad_addr); | ||
1587 | machine_data->dummy_ad->pix_fmt = 0x88882317; | ||
1588 | machine_data->dummy_ad->src_size_g_alpha = cpu_to_le32((4 << 12) | 4); | ||
1589 | machine_data->dummy_ad->aoi_size = cpu_to_le32((4 << 16) | 2); | ||
1590 | machine_data->dummy_ad->offset_xyi = 0; | ||
1591 | machine_data->dummy_ad->offset_xyd = 0; | ||
1592 | machine_data->dummy_ad->next_ad = 0; | ||
1593 | 1588 | ||
1594 | /* | 1589 | /* |
1595 | * Let DIU display splash screen if it was pre-initialized | 1590 | * Let DIU display splash screen if it was pre-initialized |
1596 | * by the bootloader, set dummy area descriptor otherwise. | 1591 | * by the bootloader, set dummy area descriptor otherwise. |
1597 | */ | 1592 | */ |
1598 | if (diu_mode == MFB_MODE0) | 1593 | if (diu_mode == MFB_MODE0) |
1599 | out_be32(&machine_data->diu_reg->desc[0], | 1594 | out_be32(&data->diu_reg->desc[0], data->dummy_ad.paddr); |
1600 | machine_data->dummy_ad->paddr); | 1595 | |
1601 | 1596 | out_be32(&data->diu_reg->desc[1], data->dummy_ad.paddr); | |
1602 | out_be32(&machine_data->diu_reg->desc[1], machine_data->dummy_ad->paddr); | 1597 | out_be32(&data->diu_reg->desc[2], data->dummy_ad.paddr); |
1603 | out_be32(&machine_data->diu_reg->desc[2], machine_data->dummy_ad->paddr); | 1598 | |
1604 | 1599 | for (i = 0; i < NUM_AOIS; i++) { | |
1605 | for (i = 0; i < ARRAY_SIZE(machine_data->fsl_diu_info); i++) { | 1600 | ret = install_fb(&data->fsl_diu_info[i]); |
1606 | machine_data->fsl_diu_info[i]->fix.smem_start = 0; | ||
1607 | mfbi = machine_data->fsl_diu_info[i]->par; | ||
1608 | mfbi->ad = (struct diu_ad *)((u32)machine_data->ad.vaddr | ||
1609 | + machine_data->ad.offset) + i; | ||
1610 | mfbi->ad->paddr = | ||
1611 | machine_data->ad.paddr + i * sizeof(struct diu_ad); | ||
1612 | ret = install_fb(machine_data->fsl_diu_info[i]); | ||
1613 | if (ret) { | 1601 | if (ret) { |
1614 | dev_err(&pdev->dev, "could not register fb %d\n", i); | 1602 | dev_err(&pdev->dev, "could not register fb %d\n", i); |
1615 | goto error; | 1603 | goto error; |
1616 | } | 1604 | } |
1617 | } | 1605 | } |
1618 | 1606 | ||
1619 | if (request_irq_local(machine_data)) { | 1607 | if (request_irq_local(data)) { |
1620 | dev_err(&pdev->dev, "could not claim irq\n"); | 1608 | dev_err(&pdev->dev, "could not claim irq\n"); |
1621 | goto error; | 1609 | goto error; |
1622 | } | 1610 | } |
1623 | 1611 | ||
1624 | sysfs_attr_init(&machine_data->dev_attr.attr); | 1612 | sysfs_attr_init(&data->dev_attr.attr); |
1625 | machine_data->dev_attr.attr.name = "monitor"; | 1613 | data->dev_attr.attr.name = "monitor"; |
1626 | machine_data->dev_attr.attr.mode = S_IRUGO|S_IWUSR; | 1614 | data->dev_attr.attr.mode = S_IRUGO|S_IWUSR; |
1627 | machine_data->dev_attr.show = show_monitor; | 1615 | data->dev_attr.show = show_monitor; |
1628 | machine_data->dev_attr.store = store_monitor; | 1616 | data->dev_attr.store = store_monitor; |
1629 | error = device_create_file(machine_data->fsl_diu_info[0]->dev, | 1617 | ret = device_create_file(&pdev->dev, &data->dev_attr); |
1630 | &machine_data->dev_attr); | 1618 | if (ret) { |
1631 | if (error) { | ||
1632 | dev_err(&pdev->dev, "could not create sysfs file %s\n", | 1619 | dev_err(&pdev->dev, "could not create sysfs file %s\n", |
1633 | machine_data->dev_attr.attr.name); | 1620 | data->dev_attr.attr.name); |
1634 | } | 1621 | } |
1635 | 1622 | ||
1636 | dev_set_drvdata(&pdev->dev, machine_data); | 1623 | dev_set_drvdata(&pdev->dev, data); |
1637 | return 0; | 1624 | return 0; |
1638 | 1625 | ||
1639 | error: | 1626 | error: |
1640 | for (i = 0; i < ARRAY_SIZE(machine_data->fsl_diu_info); i++) | 1627 | for (i = 0; i < NUM_AOIS; i++) |
1641 | uninstall_fb(machine_data->fsl_diu_info[i]); | 1628 | uninstall_fb(&data->fsl_diu_info[i]); |
1642 | 1629 | ||
1643 | if (machine_data->ad.vaddr) | 1630 | iounmap(data->diu_reg); |
1644 | free_buf(&pdev->dev, &machine_data->ad, | 1631 | |
1645 | sizeof(struct diu_ad) * FSL_AOI_NUM, 8); | 1632 | dma_free_coherent(&pdev->dev, sizeof(struct fsl_diu_data), data, |
1646 | if (machine_data->gamma.vaddr) | 1633 | data->dma_addr); |
1647 | free_buf(&pdev->dev, &machine_data->gamma, 768, 32); | ||
1648 | if (machine_data->cursor.vaddr) | ||
1649 | free_buf(&pdev->dev, &machine_data->cursor, | ||
1650 | MAX_CURS * MAX_CURS * 2, 32); | ||
1651 | if (machine_data->dummy_aoi_virt) | ||
1652 | fsl_diu_free(machine_data->dummy_aoi_virt, 64); | ||
1653 | iounmap(machine_data->diu_reg); | ||
1654 | |||
1655 | error2: | ||
1656 | for (i = 0; i < ARRAY_SIZE(machine_data->fsl_diu_info); i++) | ||
1657 | if (machine_data->fsl_diu_info[i]) | ||
1658 | framebuffer_release(machine_data->fsl_diu_info[i]); | ||
1659 | kfree(machine_data); | ||
1660 | 1634 | ||
1661 | return ret; | 1635 | return ret; |
1662 | } | 1636 | } |
1663 | 1637 | ||
1664 | static int fsl_diu_remove(struct platform_device *pdev) | 1638 | static int fsl_diu_remove(struct platform_device *pdev) |
1665 | { | 1639 | { |
1666 | struct fsl_diu_data *machine_data; | 1640 | struct fsl_diu_data *data; |
1667 | int i; | 1641 | int i; |
1668 | 1642 | ||
1669 | machine_data = dev_get_drvdata(&pdev->dev); | 1643 | data = dev_get_drvdata(&pdev->dev); |
1670 | disable_lcdc(machine_data->fsl_diu_info[0]); | 1644 | disable_lcdc(&data->fsl_diu_info[0]); |
1671 | free_irq_local(machine_data); | 1645 | free_irq_local(data); |
1672 | for (i = 0; i < ARRAY_SIZE(machine_data->fsl_diu_info); i++) | 1646 | |
1673 | uninstall_fb(machine_data->fsl_diu_info[i]); | 1647 | for (i = 0; i < NUM_AOIS; i++) |
1674 | if (machine_data->ad.vaddr) | 1648 | uninstall_fb(&data->fsl_diu_info[i]); |
1675 | free_buf(&pdev->dev, &machine_data->ad, | 1649 | |
1676 | sizeof(struct diu_ad) * FSL_AOI_NUM, 8); | 1650 | iounmap(data->diu_reg); |
1677 | if (machine_data->gamma.vaddr) | 1651 | |
1678 | free_buf(&pdev->dev, &machine_data->gamma, 768, 32); | 1652 | dma_free_coherent(&pdev->dev, sizeof(struct fsl_diu_data), data, |
1679 | if (machine_data->cursor.vaddr) | 1653 | data->dma_addr); |
1680 | free_buf(&pdev->dev, &machine_data->cursor, | ||
1681 | MAX_CURS * MAX_CURS * 2, 32); | ||
1682 | if (machine_data->dummy_aoi_virt) | ||
1683 | fsl_diu_free(machine_data->dummy_aoi_virt, 64); | ||
1684 | iounmap(machine_data->diu_reg); | ||
1685 | for (i = 0; i < ARRAY_SIZE(machine_data->fsl_diu_info); i++) | ||
1686 | if (machine_data->fsl_diu_info[i]) | ||
1687 | framebuffer_release(machine_data->fsl_diu_info[i]); | ||
1688 | kfree(machine_data); | ||
1689 | 1654 | ||
1690 | return 0; | 1655 | return 0; |
1691 | } | 1656 | } |
diff --git a/drivers/video/grvga.c b/drivers/video/grvga.c index f37e02538203..da066c210923 100644 --- a/drivers/video/grvga.c +++ b/drivers/video/grvga.c | |||
@@ -70,7 +70,7 @@ static const struct fb_videomode grvga_modedb[] = { | |||
70 | } | 70 | } |
71 | }; | 71 | }; |
72 | 72 | ||
73 | static struct fb_fix_screeninfo grvga_fix __initdata = { | 73 | static struct fb_fix_screeninfo grvga_fix __devinitdata = { |
74 | .id = "AG SVGACTRL", | 74 | .id = "AG SVGACTRL", |
75 | .type = FB_TYPE_PACKED_PIXELS, | 75 | .type = FB_TYPE_PACKED_PIXELS, |
76 | .visual = FB_VISUAL_PSEUDOCOLOR, | 76 | .visual = FB_VISUAL_PSEUDOCOLOR, |
@@ -267,7 +267,7 @@ static struct fb_ops grvga_ops = { | |||
267 | .fb_imageblit = cfb_imageblit | 267 | .fb_imageblit = cfb_imageblit |
268 | }; | 268 | }; |
269 | 269 | ||
270 | static int __init grvga_parse_custom(char *options, | 270 | static int __devinit grvga_parse_custom(char *options, |
271 | struct fb_var_screeninfo *screendata) | 271 | struct fb_var_screeninfo *screendata) |
272 | { | 272 | { |
273 | char *this_opt; | 273 | char *this_opt; |
diff --git a/drivers/video/i810/i810_main.c b/drivers/video/i810/i810_main.c index 318f6fb895b2..b83f36190cae 100644 --- a/drivers/video/i810/i810_main.c +++ b/drivers/video/i810/i810_main.c | |||
@@ -135,8 +135,8 @@ static struct pci_driver i810fb_driver = { | |||
135 | static char *mode_option __devinitdata = NULL; | 135 | static char *mode_option __devinitdata = NULL; |
136 | static int vram __devinitdata = 4; | 136 | static int vram __devinitdata = 4; |
137 | static int bpp __devinitdata = 8; | 137 | static int bpp __devinitdata = 8; |
138 | static int mtrr __devinitdata; | 138 | static bool mtrr __devinitdata; |
139 | static int accel __devinitdata; | 139 | static bool accel __devinitdata; |
140 | static int hsync1 __devinitdata; | 140 | static int hsync1 __devinitdata; |
141 | static int hsync2 __devinitdata; | 141 | static int hsync2 __devinitdata; |
142 | static int vsync1 __devinitdata; | 142 | static int vsync1 __devinitdata; |
@@ -144,10 +144,10 @@ static int vsync2 __devinitdata; | |||
144 | static int xres __devinitdata; | 144 | static int xres __devinitdata; |
145 | static int yres; | 145 | static int yres; |
146 | static int vyres __devinitdata; | 146 | static int vyres __devinitdata; |
147 | static int sync __devinitdata; | 147 | static bool sync __devinitdata; |
148 | static int extvga __devinitdata; | 148 | static bool extvga __devinitdata; |
149 | static int dcolor __devinitdata; | 149 | static bool dcolor __devinitdata; |
150 | static int ddc3 __devinitdata = 2; | 150 | static bool ddc3 __devinitdata; |
151 | 151 | ||
152 | /*------------------------------------------------------------*/ | 152 | /*------------------------------------------------------------*/ |
153 | 153 | ||
@@ -1776,7 +1776,7 @@ static void __devinit i810_init_defaults(struct i810fb_par *par, | |||
1776 | if (sync) | 1776 | if (sync) |
1777 | par->dev_flags |= ALWAYS_SYNC; | 1777 | par->dev_flags |= ALWAYS_SYNC; |
1778 | 1778 | ||
1779 | par->ddc_num = ddc3; | 1779 | par->ddc_num = (ddc3 ? 3 : 2); |
1780 | 1780 | ||
1781 | if (bpp < 8) | 1781 | if (bpp < 8) |
1782 | bpp = 8; | 1782 | bpp = 8; |
@@ -1999,7 +1999,7 @@ static int __devinit i810fb_setup(char *options) | |||
1999 | else if (!strncmp(this_opt, "dcolor", 6)) | 1999 | else if (!strncmp(this_opt, "dcolor", 6)) |
2000 | dcolor = 1; | 2000 | dcolor = 1; |
2001 | else if (!strncmp(this_opt, "ddc3", 4)) | 2001 | else if (!strncmp(this_opt, "ddc3", 4)) |
2002 | ddc3 = 3; | 2002 | ddc3 = true; |
2003 | else | 2003 | else |
2004 | mode_option = this_opt; | 2004 | mode_option = this_opt; |
2005 | } | 2005 | } |
diff --git a/drivers/video/matrox/matroxfb_base.c b/drivers/video/matrox/matroxfb_base.c index 44bf8d4a216b..401a56e250bd 100644 --- a/drivers/video/matrox/matroxfb_base.c +++ b/drivers/video/matrox/matroxfb_base.c | |||
@@ -147,7 +147,6 @@ static struct fb_var_screeninfo vesafb_defined = { | |||
147 | 39721L,48L,16L,33L,10L, | 147 | 39721L,48L,16L,33L,10L, |
148 | 96L,2L,~0, /* No sync info */ | 148 | 96L,2L,~0, /* No sync info */ |
149 | FB_VMODE_NONINTERLACED, | 149 | FB_VMODE_NONINTERLACED, |
150 | 0, {0,0,0,0,0} | ||
151 | }; | 150 | }; |
152 | 151 | ||
153 | 152 | ||
diff --git a/drivers/video/matrox/matroxfb_crtc2.c b/drivers/video/matrox/matroxfb_crtc2.c index d7112c39614b..02796a4317a9 100644 --- a/drivers/video/matrox/matroxfb_crtc2.c +++ b/drivers/video/matrox/matroxfb_crtc2.c | |||
@@ -593,7 +593,6 @@ static struct fb_var_screeninfo matroxfb_dh_defined = { | |||
593 | 39721L,48L,16L,33L,10L, | 593 | 39721L,48L,16L,33L,10L, |
594 | 96L,2,0, /* no sync info */ | 594 | 96L,2,0, /* no sync info */ |
595 | FB_VMODE_NONINTERLACED, | 595 | FB_VMODE_NONINTERLACED, |
596 | 0, {0,0,0,0,0} | ||
597 | }; | 596 | }; |
598 | 597 | ||
599 | static int matroxfb_dh_regit(const struct matrox_fb_info *minfo, | 598 | static int matroxfb_dh_regit(const struct matrox_fb_info *minfo, |
diff --git a/drivers/video/mbx/mbxfb.c b/drivers/video/mbx/mbxfb.c index 6ce34160da78..55bf6196b7a0 100644 --- a/drivers/video/mbx/mbxfb.c +++ b/drivers/video/mbx/mbxfb.c | |||
@@ -1053,18 +1053,7 @@ static struct platform_driver mbxfb_driver = { | |||
1053 | }, | 1053 | }, |
1054 | }; | 1054 | }; |
1055 | 1055 | ||
1056 | int __devinit mbxfb_init(void) | 1056 | module_platform_driver(mbxfb_driver); |
1057 | { | ||
1058 | return platform_driver_register(&mbxfb_driver); | ||
1059 | } | ||
1060 | |||
1061 | static void __devexit mbxfb_exit(void) | ||
1062 | { | ||
1063 | platform_driver_unregister(&mbxfb_driver); | ||
1064 | } | ||
1065 | |||
1066 | module_init(mbxfb_init); | ||
1067 | module_exit(mbxfb_exit); | ||
1068 | 1057 | ||
1069 | MODULE_DESCRIPTION("loadable framebuffer driver for Marathon device"); | 1058 | MODULE_DESCRIPTION("loadable framebuffer driver for Marathon device"); |
1070 | MODULE_AUTHOR("Mike Rapoport, Compulab"); | 1059 | MODULE_AUTHOR("Mike Rapoport, Compulab"); |
diff --git a/drivers/video/mxsfb.c b/drivers/video/mxsfb.c index eb3c5eea1a0f..4a89f889852d 100644 --- a/drivers/video/mxsfb.c +++ b/drivers/video/mxsfb.c | |||
@@ -902,18 +902,7 @@ static struct platform_driver mxsfb_driver = { | |||
902 | }, | 902 | }, |
903 | }; | 903 | }; |
904 | 904 | ||
905 | static int __init mxsfb_init(void) | 905 | module_platform_driver(mxsfb_driver); |
906 | { | ||
907 | return platform_driver_register(&mxsfb_driver); | ||
908 | } | ||
909 | |||
910 | static void __exit mxsfb_exit(void) | ||
911 | { | ||
912 | platform_driver_unregister(&mxsfb_driver); | ||
913 | } | ||
914 | |||
915 | module_init(mxsfb_init); | ||
916 | module_exit(mxsfb_exit); | ||
917 | 906 | ||
918 | MODULE_DESCRIPTION("Freescale mxs framebuffer driver"); | 907 | MODULE_DESCRIPTION("Freescale mxs framebuffer driver"); |
919 | MODULE_AUTHOR("Sascha Hauer, Pengutronix"); | 908 | MODULE_AUTHOR("Sascha Hauer, Pengutronix"); |
diff --git a/drivers/video/nuc900fb.c b/drivers/video/nuc900fb.c index d1fbbd888cf4..e10f551ade21 100644 --- a/drivers/video/nuc900fb.c +++ b/drivers/video/nuc900fb.c | |||
@@ -762,18 +762,7 @@ static struct platform_driver nuc900fb_driver = { | |||
762 | }, | 762 | }, |
763 | }; | 763 | }; |
764 | 764 | ||
765 | int __devinit nuc900fb_init(void) | 765 | module_platform_driver(nuc900fb_driver); |
766 | { | ||
767 | return platform_driver_register(&nuc900fb_driver); | ||
768 | } | ||
769 | |||
770 | static void __exit nuc900fb_cleanup(void) | ||
771 | { | ||
772 | platform_driver_unregister(&nuc900fb_driver); | ||
773 | } | ||
774 | |||
775 | module_init(nuc900fb_init); | ||
776 | module_exit(nuc900fb_cleanup); | ||
777 | 766 | ||
778 | MODULE_DESCRIPTION("Framebuffer driver for the NUC900"); | 767 | MODULE_DESCRIPTION("Framebuffer driver for the NUC900"); |
779 | MODULE_LICENSE("GPL"); | 768 | MODULE_LICENSE("GPL"); |
diff --git a/drivers/video/omap/lcd_ams_delta.c b/drivers/video/omap/lcd_ams_delta.c index 6978ae4ef83a..0fdd6f6873bf 100644 --- a/drivers/video/omap/lcd_ams_delta.c +++ b/drivers/video/omap/lcd_ams_delta.c | |||
@@ -198,7 +198,7 @@ static int ams_delta_panel_resume(struct platform_device *pdev) | |||
198 | return 0; | 198 | return 0; |
199 | } | 199 | } |
200 | 200 | ||
201 | struct platform_driver ams_delta_panel_driver = { | 201 | static struct platform_driver ams_delta_panel_driver = { |
202 | .probe = ams_delta_panel_probe, | 202 | .probe = ams_delta_panel_probe, |
203 | .remove = ams_delta_panel_remove, | 203 | .remove = ams_delta_panel_remove, |
204 | .suspend = ams_delta_panel_suspend, | 204 | .suspend = ams_delta_panel_suspend, |
@@ -209,15 +209,4 @@ struct platform_driver ams_delta_panel_driver = { | |||
209 | }, | 209 | }, |
210 | }; | 210 | }; |
211 | 211 | ||
212 | static int __init ams_delta_panel_drv_init(void) | 212 | module_platform_driver(ams_delta_panel_driver); |
213 | { | ||
214 | return platform_driver_register(&ams_delta_panel_driver); | ||
215 | } | ||
216 | |||
217 | static void __exit ams_delta_panel_drv_cleanup(void) | ||
218 | { | ||
219 | platform_driver_unregister(&ams_delta_panel_driver); | ||
220 | } | ||
221 | |||
222 | module_init(ams_delta_panel_drv_init); | ||
223 | module_exit(ams_delta_panel_drv_cleanup); | ||
diff --git a/drivers/video/omap/lcd_h3.c b/drivers/video/omap/lcd_h3.c index 622ad839fd9d..49bdeca81e50 100644 --- a/drivers/video/omap/lcd_h3.c +++ b/drivers/video/omap/lcd_h3.c | |||
@@ -113,7 +113,7 @@ static int h3_panel_resume(struct platform_device *pdev) | |||
113 | return 0; | 113 | return 0; |
114 | } | 114 | } |
115 | 115 | ||
116 | struct platform_driver h3_panel_driver = { | 116 | static struct platform_driver h3_panel_driver = { |
117 | .probe = h3_panel_probe, | 117 | .probe = h3_panel_probe, |
118 | .remove = h3_panel_remove, | 118 | .remove = h3_panel_remove, |
119 | .suspend = h3_panel_suspend, | 119 | .suspend = h3_panel_suspend, |
@@ -124,16 +124,4 @@ struct platform_driver h3_panel_driver = { | |||
124 | }, | 124 | }, |
125 | }; | 125 | }; |
126 | 126 | ||
127 | static int __init h3_panel_drv_init(void) | 127 | module_platform_driver(h3_panel_driver); |
128 | { | ||
129 | return platform_driver_register(&h3_panel_driver); | ||
130 | } | ||
131 | |||
132 | static void __exit h3_panel_drv_cleanup(void) | ||
133 | { | ||
134 | platform_driver_unregister(&h3_panel_driver); | ||
135 | } | ||
136 | |||
137 | module_init(h3_panel_drv_init); | ||
138 | module_exit(h3_panel_drv_cleanup); | ||
139 | |||
diff --git a/drivers/video/omap/lcd_htcherald.c b/drivers/video/omap/lcd_htcherald.c index 4802419da83b..20f477851d54 100644 --- a/drivers/video/omap/lcd_htcherald.c +++ b/drivers/video/omap/lcd_htcherald.c | |||
@@ -104,7 +104,7 @@ static int htcherald_panel_resume(struct platform_device *pdev) | |||
104 | return 0; | 104 | return 0; |
105 | } | 105 | } |
106 | 106 | ||
107 | struct platform_driver htcherald_panel_driver = { | 107 | static struct platform_driver htcherald_panel_driver = { |
108 | .probe = htcherald_panel_probe, | 108 | .probe = htcherald_panel_probe, |
109 | .remove = htcherald_panel_remove, | 109 | .remove = htcherald_panel_remove, |
110 | .suspend = htcherald_panel_suspend, | 110 | .suspend = htcherald_panel_suspend, |
@@ -115,16 +115,4 @@ struct platform_driver htcherald_panel_driver = { | |||
115 | }, | 115 | }, |
116 | }; | 116 | }; |
117 | 117 | ||
118 | static int __init htcherald_panel_drv_init(void) | 118 | module_platform_driver(htcherald_panel_driver); |
119 | { | ||
120 | return platform_driver_register(&htcherald_panel_driver); | ||
121 | } | ||
122 | |||
123 | static void __exit htcherald_panel_drv_cleanup(void) | ||
124 | { | ||
125 | platform_driver_unregister(&htcherald_panel_driver); | ||
126 | } | ||
127 | |||
128 | module_init(htcherald_panel_drv_init); | ||
129 | module_exit(htcherald_panel_drv_cleanup); | ||
130 | |||
diff --git a/drivers/video/omap/lcd_inn1510.c b/drivers/video/omap/lcd_inn1510.c index 3271f1643b26..b38b1dd15ce3 100644 --- a/drivers/video/omap/lcd_inn1510.c +++ b/drivers/video/omap/lcd_inn1510.c | |||
@@ -98,7 +98,7 @@ static int innovator1510_panel_resume(struct platform_device *pdev) | |||
98 | return 0; | 98 | return 0; |
99 | } | 99 | } |
100 | 100 | ||
101 | struct platform_driver innovator1510_panel_driver = { | 101 | static struct platform_driver innovator1510_panel_driver = { |
102 | .probe = innovator1510_panel_probe, | 102 | .probe = innovator1510_panel_probe, |
103 | .remove = innovator1510_panel_remove, | 103 | .remove = innovator1510_panel_remove, |
104 | .suspend = innovator1510_panel_suspend, | 104 | .suspend = innovator1510_panel_suspend, |
@@ -109,16 +109,4 @@ struct platform_driver innovator1510_panel_driver = { | |||
109 | }, | 109 | }, |
110 | }; | 110 | }; |
111 | 111 | ||
112 | static int __init innovator1510_panel_drv_init(void) | 112 | module_platform_driver(innovator1510_panel_driver); |
113 | { | ||
114 | return platform_driver_register(&innovator1510_panel_driver); | ||
115 | } | ||
116 | |||
117 | static void __exit innovator1510_panel_drv_cleanup(void) | ||
118 | { | ||
119 | platform_driver_unregister(&innovator1510_panel_driver); | ||
120 | } | ||
121 | |||
122 | module_init(innovator1510_panel_drv_init); | ||
123 | module_exit(innovator1510_panel_drv_cleanup); | ||
124 | |||
diff --git a/drivers/video/omap/lcd_inn1610.c b/drivers/video/omap/lcd_inn1610.c index 12cc52a70f96..7e8bd8e08a98 100644 --- a/drivers/video/omap/lcd_inn1610.c +++ b/drivers/video/omap/lcd_inn1610.c | |||
@@ -122,7 +122,7 @@ static int innovator1610_panel_resume(struct platform_device *pdev) | |||
122 | return 0; | 122 | return 0; |
123 | } | 123 | } |
124 | 124 | ||
125 | struct platform_driver innovator1610_panel_driver = { | 125 | static struct platform_driver innovator1610_panel_driver = { |
126 | .probe = innovator1610_panel_probe, | 126 | .probe = innovator1610_panel_probe, |
127 | .remove = innovator1610_panel_remove, | 127 | .remove = innovator1610_panel_remove, |
128 | .suspend = innovator1610_panel_suspend, | 128 | .suspend = innovator1610_panel_suspend, |
@@ -133,16 +133,4 @@ struct platform_driver innovator1610_panel_driver = { | |||
133 | }, | 133 | }, |
134 | }; | 134 | }; |
135 | 135 | ||
136 | static int __init innovator1610_panel_drv_init(void) | 136 | module_platform_driver(innovator1610_panel_driver); |
137 | { | ||
138 | return platform_driver_register(&innovator1610_panel_driver); | ||
139 | } | ||
140 | |||
141 | static void __exit innovator1610_panel_drv_cleanup(void) | ||
142 | { | ||
143 | platform_driver_unregister(&innovator1610_panel_driver); | ||
144 | } | ||
145 | |||
146 | module_init(innovator1610_panel_drv_init); | ||
147 | module_exit(innovator1610_panel_drv_cleanup); | ||
148 | |||
diff --git a/drivers/video/omap/lcd_mipid.c b/drivers/video/omap/lcd_mipid.c index eb381db7fe51..8d546dd55e81 100644 --- a/drivers/video/omap/lcd_mipid.c +++ b/drivers/video/omap/lcd_mipid.c | |||
@@ -603,7 +603,6 @@ static int mipid_spi_remove(struct spi_device *spi) | |||
603 | static struct spi_driver mipid_spi_driver = { | 603 | static struct spi_driver mipid_spi_driver = { |
604 | .driver = { | 604 | .driver = { |
605 | .name = MIPID_MODULE_NAME, | 605 | .name = MIPID_MODULE_NAME, |
606 | .bus = &spi_bus_type, | ||
607 | .owner = THIS_MODULE, | 606 | .owner = THIS_MODULE, |
608 | }, | 607 | }, |
609 | .probe = mipid_spi_probe, | 608 | .probe = mipid_spi_probe, |
diff --git a/drivers/video/omap/lcd_osk.c b/drivers/video/omap/lcd_osk.c index 6f8d13c41202..5914220dfa9c 100644 --- a/drivers/video/omap/lcd_osk.c +++ b/drivers/video/omap/lcd_osk.c | |||
@@ -116,7 +116,7 @@ static int osk_panel_resume(struct platform_device *pdev) | |||
116 | return 0; | 116 | return 0; |
117 | } | 117 | } |
118 | 118 | ||
119 | struct platform_driver osk_panel_driver = { | 119 | static struct platform_driver osk_panel_driver = { |
120 | .probe = osk_panel_probe, | 120 | .probe = osk_panel_probe, |
121 | .remove = osk_panel_remove, | 121 | .remove = osk_panel_remove, |
122 | .suspend = osk_panel_suspend, | 122 | .suspend = osk_panel_suspend, |
@@ -127,16 +127,4 @@ struct platform_driver osk_panel_driver = { | |||
127 | }, | 127 | }, |
128 | }; | 128 | }; |
129 | 129 | ||
130 | static int __init osk_panel_drv_init(void) | 130 | module_platform_driver(osk_panel_driver); |
131 | { | ||
132 | return platform_driver_register(&osk_panel_driver); | ||
133 | } | ||
134 | |||
135 | static void __exit osk_panel_drv_cleanup(void) | ||
136 | { | ||
137 | platform_driver_unregister(&osk_panel_driver); | ||
138 | } | ||
139 | |||
140 | module_init(osk_panel_drv_init); | ||
141 | module_exit(osk_panel_drv_cleanup); | ||
142 | |||
diff --git a/drivers/video/omap/lcd_palmte.c b/drivers/video/omap/lcd_palmte.c index 4cb301750d02..88c31eb0cd6c 100644 --- a/drivers/video/omap/lcd_palmte.c +++ b/drivers/video/omap/lcd_palmte.c | |||
@@ -97,7 +97,7 @@ static int palmte_panel_resume(struct platform_device *pdev) | |||
97 | return 0; | 97 | return 0; |
98 | } | 98 | } |
99 | 99 | ||
100 | struct platform_driver palmte_panel_driver = { | 100 | static struct platform_driver palmte_panel_driver = { |
101 | .probe = palmte_panel_probe, | 101 | .probe = palmte_panel_probe, |
102 | .remove = palmte_panel_remove, | 102 | .remove = palmte_panel_remove, |
103 | .suspend = palmte_panel_suspend, | 103 | .suspend = palmte_panel_suspend, |
@@ -108,16 +108,4 @@ struct platform_driver palmte_panel_driver = { | |||
108 | }, | 108 | }, |
109 | }; | 109 | }; |
110 | 110 | ||
111 | static int __init palmte_panel_drv_init(void) | 111 | module_platform_driver(palmte_panel_driver); |
112 | { | ||
113 | return platform_driver_register(&palmte_panel_driver); | ||
114 | } | ||
115 | |||
116 | static void __exit palmte_panel_drv_cleanup(void) | ||
117 | { | ||
118 | platform_driver_unregister(&palmte_panel_driver); | ||
119 | } | ||
120 | |||
121 | module_init(palmte_panel_drv_init); | ||
122 | module_exit(palmte_panel_drv_cleanup); | ||
123 | |||
diff --git a/drivers/video/omap/lcd_palmtt.c b/drivers/video/omap/lcd_palmtt.c index b51b332e5a2b..aaf3c8ba1243 100644 --- a/drivers/video/omap/lcd_palmtt.c +++ b/drivers/video/omap/lcd_palmtt.c | |||
@@ -102,7 +102,7 @@ static int palmtt_panel_resume(struct platform_device *pdev) | |||
102 | return 0; | 102 | return 0; |
103 | } | 103 | } |
104 | 104 | ||
105 | struct platform_driver palmtt_panel_driver = { | 105 | static struct platform_driver palmtt_panel_driver = { |
106 | .probe = palmtt_panel_probe, | 106 | .probe = palmtt_panel_probe, |
107 | .remove = palmtt_panel_remove, | 107 | .remove = palmtt_panel_remove, |
108 | .suspend = palmtt_panel_suspend, | 108 | .suspend = palmtt_panel_suspend, |
@@ -113,15 +113,4 @@ struct platform_driver palmtt_panel_driver = { | |||
113 | }, | 113 | }, |
114 | }; | 114 | }; |
115 | 115 | ||
116 | static int __init palmtt_panel_drv_init(void) | 116 | module_platform_driver(palmtt_panel_driver); |
117 | { | ||
118 | return platform_driver_register(&palmtt_panel_driver); | ||
119 | } | ||
120 | |||
121 | static void __exit palmtt_panel_drv_cleanup(void) | ||
122 | { | ||
123 | platform_driver_unregister(&palmtt_panel_driver); | ||
124 | } | ||
125 | |||
126 | module_init(palmtt_panel_drv_init); | ||
127 | module_exit(palmtt_panel_drv_cleanup); | ||
diff --git a/drivers/video/omap/lcd_palmz71.c b/drivers/video/omap/lcd_palmz71.c index 2334e56536bc..3b7d8aa1cf34 100644 --- a/drivers/video/omap/lcd_palmz71.c +++ b/drivers/video/omap/lcd_palmz71.c | |||
@@ -98,7 +98,7 @@ static int palmz71_panel_resume(struct platform_device *pdev) | |||
98 | return 0; | 98 | return 0; |
99 | } | 99 | } |
100 | 100 | ||
101 | struct platform_driver palmz71_panel_driver = { | 101 | static struct platform_driver palmz71_panel_driver = { |
102 | .probe = palmz71_panel_probe, | 102 | .probe = palmz71_panel_probe, |
103 | .remove = palmz71_panel_remove, | 103 | .remove = palmz71_panel_remove, |
104 | .suspend = palmz71_panel_suspend, | 104 | .suspend = palmz71_panel_suspend, |
@@ -109,15 +109,4 @@ struct platform_driver palmz71_panel_driver = { | |||
109 | }, | 109 | }, |
110 | }; | 110 | }; |
111 | 111 | ||
112 | static int __init palmz71_panel_drv_init(void) | 112 | module_platform_driver(palmz71_panel_driver); |
113 | { | ||
114 | return platform_driver_register(&palmz71_panel_driver); | ||
115 | } | ||
116 | |||
117 | static void __exit palmz71_panel_drv_cleanup(void) | ||
118 | { | ||
119 | platform_driver_unregister(&palmz71_panel_driver); | ||
120 | } | ||
121 | |||
122 | module_init(palmz71_panel_drv_init); | ||
123 | module_exit(palmz71_panel_drv_cleanup); | ||
diff --git a/drivers/video/omap2/displays/Kconfig b/drivers/video/omap2/displays/Kconfig index 8d8e1fe1901c..74d29b552901 100644 --- a/drivers/video/omap2/displays/Kconfig +++ b/drivers/video/omap2/displays/Kconfig | |||
@@ -41,7 +41,7 @@ config PANEL_NEC_NL8048HL11_01B | |||
41 | 41 | ||
42 | config PANEL_PICODLP | 42 | config PANEL_PICODLP |
43 | tristate "TI PICO DLP mini-projector" | 43 | tristate "TI PICO DLP mini-projector" |
44 | depends on OMAP2_DSS && I2C | 44 | depends on OMAP2_DSS_DPI && I2C |
45 | help | 45 | help |
46 | A mini-projector used in TI's SDP4430 and EVM boards | 46 | A mini-projector used in TI's SDP4430 and EVM boards |
47 | For more info please visit http://www.dlp.com/projector/ | 47 | For more info please visit http://www.dlp.com/projector/ |
diff --git a/drivers/video/omap2/displays/panel-acx565akm.c b/drivers/video/omap2/displays/panel-acx565akm.c index dbd59b8e5b36..51a87e149e24 100644 --- a/drivers/video/omap2/displays/panel-acx565akm.c +++ b/drivers/video/omap2/displays/panel-acx565akm.c | |||
@@ -803,7 +803,6 @@ static int acx565akm_spi_remove(struct spi_device *spi) | |||
803 | static struct spi_driver acx565akm_spi_driver = { | 803 | static struct spi_driver acx565akm_spi_driver = { |
804 | .driver = { | 804 | .driver = { |
805 | .name = "acx565akm", | 805 | .name = "acx565akm", |
806 | .bus = &spi_bus_type, | ||
807 | .owner = THIS_MODULE, | 806 | .owner = THIS_MODULE, |
808 | }, | 807 | }, |
809 | .probe = acx565akm_spi_probe, | 808 | .probe = acx565akm_spi_probe, |
diff --git a/drivers/video/omap2/displays/panel-generic-dpi.c b/drivers/video/omap2/displays/panel-generic-dpi.c index 519c47d2057f..28b9a6d61b0f 100644 --- a/drivers/video/omap2/displays/panel-generic-dpi.c +++ b/drivers/video/omap2/displays/panel-generic-dpi.c | |||
@@ -297,6 +297,72 @@ static struct panel_config generic_dpi_panels[] = { | |||
297 | 297 | ||
298 | .name = "apollon", | 298 | .name = "apollon", |
299 | }, | 299 | }, |
300 | /* FocalTech ETM070003DH6 */ | ||
301 | { | ||
302 | { | ||
303 | .x_res = 800, | ||
304 | .y_res = 480, | ||
305 | |||
306 | .pixel_clock = 28000, | ||
307 | |||
308 | .hsw = 48, | ||
309 | .hfp = 40, | ||
310 | .hbp = 40, | ||
311 | |||
312 | .vsw = 3, | ||
313 | .vfp = 13, | ||
314 | .vbp = 29, | ||
315 | }, | ||
316 | .config = OMAP_DSS_LCD_TFT | OMAP_DSS_LCD_IVS | | ||
317 | OMAP_DSS_LCD_IHS, | ||
318 | .name = "focaltech_etm070003dh6", | ||
319 | }, | ||
320 | |||
321 | /* Microtips Technologies - UMSH-8173MD */ | ||
322 | { | ||
323 | { | ||
324 | .x_res = 800, | ||
325 | .y_res = 480, | ||
326 | |||
327 | .pixel_clock = 34560, | ||
328 | |||
329 | .hsw = 13, | ||
330 | .hfp = 101, | ||
331 | .hbp = 101, | ||
332 | |||
333 | .vsw = 23, | ||
334 | .vfp = 1, | ||
335 | .vbp = 1, | ||
336 | }, | ||
337 | .acbi = 0x0, | ||
338 | .acb = 0x0, | ||
339 | .config = OMAP_DSS_LCD_TFT | OMAP_DSS_LCD_IVS | | ||
340 | OMAP_DSS_LCD_IHS | OMAP_DSS_LCD_IPC, | ||
341 | .power_on_delay = 0, | ||
342 | .power_off_delay = 0, | ||
343 | .name = "microtips_umsh_8173md", | ||
344 | }, | ||
345 | |||
346 | /* OrtusTech COM43H4M10XTC */ | ||
347 | { | ||
348 | { | ||
349 | .x_res = 480, | ||
350 | .y_res = 272, | ||
351 | |||
352 | .pixel_clock = 8000, | ||
353 | |||
354 | .hsw = 41, | ||
355 | .hfp = 8, | ||
356 | .hbp = 4, | ||
357 | |||
358 | .vsw = 10, | ||
359 | .vfp = 4, | ||
360 | .vbp = 2, | ||
361 | }, | ||
362 | .config = OMAP_DSS_LCD_TFT, | ||
363 | |||
364 | .name = "ortustech_com43h4m10xtc", | ||
365 | }, | ||
300 | }; | 366 | }; |
301 | 367 | ||
302 | struct panel_drv_data { | 368 | struct panel_drv_data { |
diff --git a/drivers/video/omap2/displays/panel-n8x0.c b/drivers/video/omap2/displays/panel-n8x0.c index 150e8bae35a1..dc9408dc93d1 100644 --- a/drivers/video/omap2/displays/panel-n8x0.c +++ b/drivers/video/omap2/displays/panel-n8x0.c | |||
@@ -708,7 +708,6 @@ static int mipid_spi_remove(struct spi_device *spi) | |||
708 | static struct spi_driver mipid_spi_driver = { | 708 | static struct spi_driver mipid_spi_driver = { |
709 | .driver = { | 709 | .driver = { |
710 | .name = "lcd_mipid", | 710 | .name = "lcd_mipid", |
711 | .bus = &spi_bus_type, | ||
712 | .owner = THIS_MODULE, | 711 | .owner = THIS_MODULE, |
713 | }, | 712 | }, |
714 | .probe = mipid_spi_probe, | 713 | .probe = mipid_spi_probe, |
diff --git a/drivers/video/omap2/displays/panel-nec-nl8048hl11-01b.c b/drivers/video/omap2/displays/panel-nec-nl8048hl11-01b.c index 2ba9d0ca187c..0eb31caddca8 100644 --- a/drivers/video/omap2/displays/panel-nec-nl8048hl11-01b.c +++ b/drivers/video/omap2/displays/panel-nec-nl8048hl11-01b.c | |||
@@ -163,50 +163,93 @@ static void nec_8048_panel_remove(struct omap_dss_device *dssdev) | |||
163 | kfree(necd); | 163 | kfree(necd); |
164 | } | 164 | } |
165 | 165 | ||
166 | static int nec_8048_panel_enable(struct omap_dss_device *dssdev) | 166 | static int nec_8048_panel_power_on(struct omap_dss_device *dssdev) |
167 | { | 167 | { |
168 | int r = 0; | 168 | int r; |
169 | struct nec_8048_data *necd = dev_get_drvdata(&dssdev->dev); | 169 | struct nec_8048_data *necd = dev_get_drvdata(&dssdev->dev); |
170 | struct backlight_device *bl = necd->bl; | 170 | struct backlight_device *bl = necd->bl; |
171 | 171 | ||
172 | if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE) | ||
173 | return 0; | ||
174 | |||
175 | r = omapdss_dpi_display_enable(dssdev); | ||
176 | if (r) | ||
177 | goto err0; | ||
178 | |||
172 | if (dssdev->platform_enable) { | 179 | if (dssdev->platform_enable) { |
173 | r = dssdev->platform_enable(dssdev); | 180 | r = dssdev->platform_enable(dssdev); |
174 | if (r) | 181 | if (r) |
175 | return r; | 182 | goto err1; |
176 | } | 183 | } |
177 | 184 | ||
178 | r = nec_8048_bl_update_status(bl); | 185 | r = nec_8048_bl_update_status(bl); |
179 | if (r < 0) | 186 | if (r < 0) |
180 | dev_err(&dssdev->dev, "failed to set lcd brightness\n"); | 187 | dev_err(&dssdev->dev, "failed to set lcd brightness\n"); |
181 | 188 | ||
182 | r = omapdss_dpi_display_enable(dssdev); | 189 | return 0; |
183 | 190 | err1: | |
191 | omapdss_dpi_display_disable(dssdev); | ||
192 | err0: | ||
184 | return r; | 193 | return r; |
185 | } | 194 | } |
186 | 195 | ||
187 | static void nec_8048_panel_disable(struct omap_dss_device *dssdev) | 196 | static void nec_8048_panel_power_off(struct omap_dss_device *dssdev) |
188 | { | 197 | { |
189 | struct nec_8048_data *necd = dev_get_drvdata(&dssdev->dev); | 198 | struct nec_8048_data *necd = dev_get_drvdata(&dssdev->dev); |
190 | struct backlight_device *bl = necd->bl; | 199 | struct backlight_device *bl = necd->bl; |
191 | 200 | ||
192 | omapdss_dpi_display_disable(dssdev); | 201 | if (dssdev->state != OMAP_DSS_DISPLAY_ACTIVE) |
202 | return; | ||
193 | 203 | ||
194 | bl->props.brightness = 0; | 204 | bl->props.brightness = 0; |
195 | nec_8048_bl_update_status(bl); | 205 | nec_8048_bl_update_status(bl); |
196 | 206 | ||
197 | if (dssdev->platform_disable) | 207 | if (dssdev->platform_disable) |
198 | dssdev->platform_disable(dssdev); | 208 | dssdev->platform_disable(dssdev); |
209 | |||
210 | omapdss_dpi_display_disable(dssdev); | ||
211 | } | ||
212 | |||
213 | static int nec_8048_panel_enable(struct omap_dss_device *dssdev) | ||
214 | { | ||
215 | int r; | ||
216 | |||
217 | r = nec_8048_panel_power_on(dssdev); | ||
218 | if (r) | ||
219 | return r; | ||
220 | |||
221 | dssdev->state = OMAP_DSS_DISPLAY_ACTIVE; | ||
222 | |||
223 | return 0; | ||
224 | } | ||
225 | |||
226 | static void nec_8048_panel_disable(struct omap_dss_device *dssdev) | ||
227 | { | ||
228 | nec_8048_panel_power_off(dssdev); | ||
229 | |||
230 | dssdev->state = OMAP_DSS_DISPLAY_DISABLED; | ||
199 | } | 231 | } |
200 | 232 | ||
201 | static int nec_8048_panel_suspend(struct omap_dss_device *dssdev) | 233 | static int nec_8048_panel_suspend(struct omap_dss_device *dssdev) |
202 | { | 234 | { |
203 | nec_8048_panel_disable(dssdev); | 235 | nec_8048_panel_power_off(dssdev); |
236 | |||
237 | dssdev->state = OMAP_DSS_DISPLAY_SUSPENDED; | ||
238 | |||
204 | return 0; | 239 | return 0; |
205 | } | 240 | } |
206 | 241 | ||
207 | static int nec_8048_panel_resume(struct omap_dss_device *dssdev) | 242 | static int nec_8048_panel_resume(struct omap_dss_device *dssdev) |
208 | { | 243 | { |
209 | return nec_8048_panel_enable(dssdev); | 244 | int r; |
245 | |||
246 | r = nec_8048_panel_power_on(dssdev); | ||
247 | if (r) | ||
248 | return r; | ||
249 | |||
250 | dssdev->state = OMAP_DSS_DISPLAY_ACTIVE; | ||
251 | |||
252 | return 0; | ||
210 | } | 253 | } |
211 | 254 | ||
212 | static int nec_8048_recommended_bpp(struct omap_dss_device *dssdev) | 255 | static int nec_8048_recommended_bpp(struct omap_dss_device *dssdev) |
@@ -303,7 +346,6 @@ static struct spi_driver nec_8048_spi_driver = { | |||
303 | .resume = nec_8048_spi_resume, | 346 | .resume = nec_8048_spi_resume, |
304 | .driver = { | 347 | .driver = { |
305 | .name = "nec_8048_spi", | 348 | .name = "nec_8048_spi", |
306 | .bus = &spi_bus_type, | ||
307 | .owner = THIS_MODULE, | 349 | .owner = THIS_MODULE, |
308 | }, | 350 | }, |
309 | }; | 351 | }; |
diff --git a/drivers/video/omap2/displays/panel-taal.c b/drivers/video/omap2/displays/panel-taal.c index 80c3f6ab1a94..00c5c615585f 100644 --- a/drivers/video/omap2/displays/panel-taal.c +++ b/drivers/video/omap2/displays/panel-taal.c | |||
@@ -198,12 +198,6 @@ struct taal_data { | |||
198 | bool te_enabled; | 198 | bool te_enabled; |
199 | 199 | ||
200 | atomic_t do_update; | 200 | atomic_t do_update; |
201 | struct { | ||
202 | u16 x; | ||
203 | u16 y; | ||
204 | u16 w; | ||
205 | u16 h; | ||
206 | } update_region; | ||
207 | int channel; | 201 | int channel; |
208 | 202 | ||
209 | struct delayed_work te_timeout_work; | 203 | struct delayed_work te_timeout_work; |
@@ -1188,6 +1182,10 @@ static int taal_power_on(struct omap_dss_device *dssdev) | |||
1188 | if (r) | 1182 | if (r) |
1189 | goto err; | 1183 | goto err; |
1190 | 1184 | ||
1185 | r = dsi_enable_video_output(dssdev, td->channel); | ||
1186 | if (r) | ||
1187 | goto err; | ||
1188 | |||
1191 | td->enabled = 1; | 1189 | td->enabled = 1; |
1192 | 1190 | ||
1193 | if (!td->intro_printed) { | 1191 | if (!td->intro_printed) { |
@@ -1217,6 +1215,8 @@ static void taal_power_off(struct omap_dss_device *dssdev) | |||
1217 | struct taal_data *td = dev_get_drvdata(&dssdev->dev); | 1215 | struct taal_data *td = dev_get_drvdata(&dssdev->dev); |
1218 | int r; | 1216 | int r; |
1219 | 1217 | ||
1218 | dsi_disable_video_output(dssdev, td->channel); | ||
1219 | |||
1220 | r = taal_dcs_write_0(td, MIPI_DCS_SET_DISPLAY_OFF); | 1220 | r = taal_dcs_write_0(td, MIPI_DCS_SET_DISPLAY_OFF); |
1221 | if (!r) | 1221 | if (!r) |
1222 | r = taal_sleep_in(td); | 1222 | r = taal_sleep_in(td); |
@@ -1394,12 +1394,8 @@ static irqreturn_t taal_te_isr(int irq, void *data) | |||
1394 | if (old) { | 1394 | if (old) { |
1395 | cancel_delayed_work(&td->te_timeout_work); | 1395 | cancel_delayed_work(&td->te_timeout_work); |
1396 | 1396 | ||
1397 | r = omap_dsi_update(dssdev, td->channel, | 1397 | r = omap_dsi_update(dssdev, td->channel, taal_framedone_cb, |
1398 | td->update_region.x, | 1398 | dssdev); |
1399 | td->update_region.y, | ||
1400 | td->update_region.w, | ||
1401 | td->update_region.h, | ||
1402 | taal_framedone_cb, dssdev); | ||
1403 | if (r) | 1399 | if (r) |
1404 | goto err; | 1400 | goto err; |
1405 | } | 1401 | } |
@@ -1444,26 +1440,20 @@ static int taal_update(struct omap_dss_device *dssdev, | |||
1444 | goto err; | 1440 | goto err; |
1445 | } | 1441 | } |
1446 | 1442 | ||
1447 | r = omap_dsi_prepare_update(dssdev, &x, &y, &w, &h, true); | 1443 | /* XXX no need to send this every frame, but dsi break if not done */ |
1448 | if (r) | 1444 | r = taal_set_update_window(td, 0, 0, |
1449 | goto err; | 1445 | td->panel_config->timings.x_res, |
1450 | 1446 | td->panel_config->timings.y_res); | |
1451 | r = taal_set_update_window(td, x, y, w, h); | ||
1452 | if (r) | 1447 | if (r) |
1453 | goto err; | 1448 | goto err; |
1454 | 1449 | ||
1455 | if (td->te_enabled && panel_data->use_ext_te) { | 1450 | if (td->te_enabled && panel_data->use_ext_te) { |
1456 | td->update_region.x = x; | ||
1457 | td->update_region.y = y; | ||
1458 | td->update_region.w = w; | ||
1459 | td->update_region.h = h; | ||
1460 | barrier(); | ||
1461 | schedule_delayed_work(&td->te_timeout_work, | 1451 | schedule_delayed_work(&td->te_timeout_work, |
1462 | msecs_to_jiffies(250)); | 1452 | msecs_to_jiffies(250)); |
1463 | atomic_set(&td->do_update, 1); | 1453 | atomic_set(&td->do_update, 1); |
1464 | } else { | 1454 | } else { |
1465 | r = omap_dsi_update(dssdev, td->channel, x, y, w, h, | 1455 | r = omap_dsi_update(dssdev, td->channel, taal_framedone_cb, |
1466 | taal_framedone_cb, dssdev); | 1456 | dssdev); |
1467 | if (r) | 1457 | if (r) |
1468 | goto err; | 1458 | goto err; |
1469 | } | 1459 | } |
diff --git a/drivers/video/omap2/displays/panel-tpo-td043mtea1.c b/drivers/video/omap2/displays/panel-tpo-td043mtea1.c index 2462b9ec6662..e6649aa89591 100644 --- a/drivers/video/omap2/displays/panel-tpo-td043mtea1.c +++ b/drivers/video/omap2/displays/panel-tpo-td043mtea1.c | |||
@@ -512,7 +512,6 @@ static int __devexit tpo_td043_spi_remove(struct spi_device *spi) | |||
512 | static struct spi_driver tpo_td043_spi_driver = { | 512 | static struct spi_driver tpo_td043_spi_driver = { |
513 | .driver = { | 513 | .driver = { |
514 | .name = "tpo_td043mtea1_panel_spi", | 514 | .name = "tpo_td043mtea1_panel_spi", |
515 | .bus = &spi_bus_type, | ||
516 | .owner = THIS_MODULE, | 515 | .owner = THIS_MODULE, |
517 | }, | 516 | }, |
518 | .probe = tpo_td043_spi_probe, | 517 | .probe = tpo_td043_spi_probe, |
diff --git a/drivers/video/omap2/dss/Makefile b/drivers/video/omap2/dss/Makefile index bd34ac5b2026..5c450b0f94d0 100644 --- a/drivers/video/omap2/dss/Makefile +++ b/drivers/video/omap2/dss/Makefile | |||
@@ -1,5 +1,6 @@ | |||
1 | obj-$(CONFIG_OMAP2_DSS) += omapdss.o | 1 | obj-$(CONFIG_OMAP2_DSS) += omapdss.o |
2 | omapdss-y := core.o dss.o dss_features.o dispc.o display.o manager.o overlay.o | 2 | omapdss-y := core.o dss.o dss_features.o dispc.o dispc_coefs.o display.o \ |
3 | manager.o overlay.o apply.o | ||
3 | omapdss-$(CONFIG_OMAP2_DSS_DPI) += dpi.o | 4 | omapdss-$(CONFIG_OMAP2_DSS_DPI) += dpi.o |
4 | omapdss-$(CONFIG_OMAP2_DSS_RFBI) += rfbi.o | 5 | omapdss-$(CONFIG_OMAP2_DSS_RFBI) += rfbi.o |
5 | omapdss-$(CONFIG_OMAP2_DSS_VENC) += venc.o | 6 | omapdss-$(CONFIG_OMAP2_DSS_VENC) += venc.o |
diff --git a/drivers/video/omap2/dss/apply.c b/drivers/video/omap2/dss/apply.c new file mode 100644 index 000000000000..052dc874cd3d --- /dev/null +++ b/drivers/video/omap2/dss/apply.c | |||
@@ -0,0 +1,1324 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2011 Texas Instruments | ||
3 | * Author: Tomi Valkeinen <tomi.valkeinen@ti.com> | ||
4 | * | ||
5 | * This program is free software; you can redistribute it and/or modify it | ||
6 | * under the terms of the GNU General Public License version 2 as published by | ||
7 | * the Free Software Foundation. | ||
8 | * | ||
9 | * This program is distributed in the hope that it will be useful, but WITHOUT | ||
10 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
11 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
12 | * more details. | ||
13 | * | ||
14 | * You should have received a copy of the GNU General Public License along with | ||
15 | * this program. If not, see <http://www.gnu.org/licenses/>. | ||
16 | */ | ||
17 | |||
18 | #define DSS_SUBSYS_NAME "APPLY" | ||
19 | |||
20 | #include <linux/kernel.h> | ||
21 | #include <linux/slab.h> | ||
22 | #include <linux/spinlock.h> | ||
23 | #include <linux/jiffies.h> | ||
24 | |||
25 | #include <video/omapdss.h> | ||
26 | |||
27 | #include "dss.h" | ||
28 | #include "dss_features.h" | ||
29 | |||
30 | /* | ||
31 | * We have 4 levels of cache for the dispc settings. First two are in SW and | ||
32 | * the latter two in HW. | ||
33 | * | ||
34 | * set_info() | ||
35 | * v | ||
36 | * +--------------------+ | ||
37 | * | user_info | | ||
38 | * +--------------------+ | ||
39 | * v | ||
40 | * apply() | ||
41 | * v | ||
42 | * +--------------------+ | ||
43 | * | info | | ||
44 | * +--------------------+ | ||
45 | * v | ||
46 | * write_regs() | ||
47 | * v | ||
48 | * +--------------------+ | ||
49 | * | shadow registers | | ||
50 | * +--------------------+ | ||
51 | * v | ||
52 | * VFP or lcd/digit_enable | ||
53 | * v | ||
54 | * +--------------------+ | ||
55 | * | registers | | ||
56 | * +--------------------+ | ||
57 | */ | ||
58 | |||
59 | struct ovl_priv_data { | ||
60 | |||
61 | bool user_info_dirty; | ||
62 | struct omap_overlay_info user_info; | ||
63 | |||
64 | bool info_dirty; | ||
65 | struct omap_overlay_info info; | ||
66 | |||
67 | bool shadow_info_dirty; | ||
68 | |||
69 | bool extra_info_dirty; | ||
70 | bool shadow_extra_info_dirty; | ||
71 | |||
72 | bool enabled; | ||
73 | enum omap_channel channel; | ||
74 | u32 fifo_low, fifo_high; | ||
75 | |||
76 | /* | ||
77 | * True if overlay is to be enabled. Used to check and calculate configs | ||
78 | * for the overlay before it is enabled in the HW. | ||
79 | */ | ||
80 | bool enabling; | ||
81 | }; | ||
82 | |||
83 | struct mgr_priv_data { | ||
84 | |||
85 | bool user_info_dirty; | ||
86 | struct omap_overlay_manager_info user_info; | ||
87 | |||
88 | bool info_dirty; | ||
89 | struct omap_overlay_manager_info info; | ||
90 | |||
91 | bool shadow_info_dirty; | ||
92 | |||
93 | /* If true, GO bit is up and shadow registers cannot be written. | ||
94 | * Never true for manual update displays */ | ||
95 | bool busy; | ||
96 | |||
97 | /* If true, dispc output is enabled */ | ||
98 | bool updating; | ||
99 | |||
100 | /* If true, a display is enabled using this manager */ | ||
101 | bool enabled; | ||
102 | }; | ||
103 | |||
104 | static struct { | ||
105 | struct ovl_priv_data ovl_priv_data_array[MAX_DSS_OVERLAYS]; | ||
106 | struct mgr_priv_data mgr_priv_data_array[MAX_DSS_MANAGERS]; | ||
107 | |||
108 | bool irq_enabled; | ||
109 | } dss_data; | ||
110 | |||
111 | /* protects dss_data */ | ||
112 | static spinlock_t data_lock; | ||
113 | /* lock for blocking functions */ | ||
114 | static DEFINE_MUTEX(apply_lock); | ||
115 | static DECLARE_COMPLETION(extra_updated_completion); | ||
116 | |||
117 | static void dss_register_vsync_isr(void); | ||
118 | |||
119 | static struct ovl_priv_data *get_ovl_priv(struct omap_overlay *ovl) | ||
120 | { | ||
121 | return &dss_data.ovl_priv_data_array[ovl->id]; | ||
122 | } | ||
123 | |||
124 | static struct mgr_priv_data *get_mgr_priv(struct omap_overlay_manager *mgr) | ||
125 | { | ||
126 | return &dss_data.mgr_priv_data_array[mgr->id]; | ||
127 | } | ||
128 | |||
129 | void dss_apply_init(void) | ||
130 | { | ||
131 | const int num_ovls = dss_feat_get_num_ovls(); | ||
132 | int i; | ||
133 | |||
134 | spin_lock_init(&data_lock); | ||
135 | |||
136 | for (i = 0; i < num_ovls; ++i) { | ||
137 | struct ovl_priv_data *op; | ||
138 | |||
139 | op = &dss_data.ovl_priv_data_array[i]; | ||
140 | |||
141 | op->info.global_alpha = 255; | ||
142 | |||
143 | switch (i) { | ||
144 | case 0: | ||
145 | op->info.zorder = 0; | ||
146 | break; | ||
147 | case 1: | ||
148 | op->info.zorder = | ||
149 | dss_has_feature(FEAT_ALPHA_FREE_ZORDER) ? 3 : 0; | ||
150 | break; | ||
151 | case 2: | ||
152 | op->info.zorder = | ||
153 | dss_has_feature(FEAT_ALPHA_FREE_ZORDER) ? 2 : 0; | ||
154 | break; | ||
155 | case 3: | ||
156 | op->info.zorder = | ||
157 | dss_has_feature(FEAT_ALPHA_FREE_ZORDER) ? 1 : 0; | ||
158 | break; | ||
159 | } | ||
160 | |||
161 | op->user_info = op->info; | ||
162 | } | ||
163 | } | ||
164 | |||
165 | static bool ovl_manual_update(struct omap_overlay *ovl) | ||
166 | { | ||
167 | return ovl->manager->device->caps & OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE; | ||
168 | } | ||
169 | |||
170 | static bool mgr_manual_update(struct omap_overlay_manager *mgr) | ||
171 | { | ||
172 | return mgr->device->caps & OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE; | ||
173 | } | ||
174 | |||
175 | static int dss_check_settings_low(struct omap_overlay_manager *mgr, | ||
176 | struct omap_dss_device *dssdev, bool applying) | ||
177 | { | ||
178 | struct omap_overlay_info *oi; | ||
179 | struct omap_overlay_manager_info *mi; | ||
180 | struct omap_overlay *ovl; | ||
181 | struct omap_overlay_info *ois[MAX_DSS_OVERLAYS]; | ||
182 | struct ovl_priv_data *op; | ||
183 | struct mgr_priv_data *mp; | ||
184 | |||
185 | mp = get_mgr_priv(mgr); | ||
186 | |||
187 | if (applying && mp->user_info_dirty) | ||
188 | mi = &mp->user_info; | ||
189 | else | ||
190 | mi = &mp->info; | ||
191 | |||
192 | /* collect the infos to be tested into the array */ | ||
193 | list_for_each_entry(ovl, &mgr->overlays, list) { | ||
194 | op = get_ovl_priv(ovl); | ||
195 | |||
196 | if (!op->enabled && !op->enabling) | ||
197 | oi = NULL; | ||
198 | else if (applying && op->user_info_dirty) | ||
199 | oi = &op->user_info; | ||
200 | else | ||
201 | oi = &op->info; | ||
202 | |||
203 | ois[ovl->id] = oi; | ||
204 | } | ||
205 | |||
206 | return dss_mgr_check(mgr, dssdev, mi, ois); | ||
207 | } | ||
208 | |||
209 | /* | ||
210 | * check manager and overlay settings using overlay_info from data->info | ||
211 | */ | ||
212 | static int dss_check_settings(struct omap_overlay_manager *mgr, | ||
213 | struct omap_dss_device *dssdev) | ||
214 | { | ||
215 | return dss_check_settings_low(mgr, dssdev, false); | ||
216 | } | ||
217 | |||
218 | /* | ||
219 | * check manager and overlay settings using overlay_info from ovl->info if | ||
220 | * dirty and from data->info otherwise | ||
221 | */ | ||
222 | static int dss_check_settings_apply(struct omap_overlay_manager *mgr, | ||
223 | struct omap_dss_device *dssdev) | ||
224 | { | ||
225 | return dss_check_settings_low(mgr, dssdev, true); | ||
226 | } | ||
227 | |||
228 | static bool need_isr(void) | ||
229 | { | ||
230 | const int num_mgrs = dss_feat_get_num_mgrs(); | ||
231 | int i; | ||
232 | |||
233 | for (i = 0; i < num_mgrs; ++i) { | ||
234 | struct omap_overlay_manager *mgr; | ||
235 | struct mgr_priv_data *mp; | ||
236 | struct omap_overlay *ovl; | ||
237 | |||
238 | mgr = omap_dss_get_overlay_manager(i); | ||
239 | mp = get_mgr_priv(mgr); | ||
240 | |||
241 | if (!mp->enabled) | ||
242 | continue; | ||
243 | |||
244 | if (mgr_manual_update(mgr)) { | ||
245 | /* to catch FRAMEDONE */ | ||
246 | if (mp->updating) | ||
247 | return true; | ||
248 | } else { | ||
249 | /* to catch GO bit going down */ | ||
250 | if (mp->busy) | ||
251 | return true; | ||
252 | |||
253 | /* to write new values to registers */ | ||
254 | if (mp->info_dirty) | ||
255 | return true; | ||
256 | |||
257 | /* to set GO bit */ | ||
258 | if (mp->shadow_info_dirty) | ||
259 | return true; | ||
260 | |||
261 | list_for_each_entry(ovl, &mgr->overlays, list) { | ||
262 | struct ovl_priv_data *op; | ||
263 | |||
264 | op = get_ovl_priv(ovl); | ||
265 | |||
266 | /* | ||
267 | * NOTE: we check extra_info flags even for | ||
268 | * disabled overlays, as extra_infos need to be | ||
269 | * always written. | ||
270 | */ | ||
271 | |||
272 | /* to write new values to registers */ | ||
273 | if (op->extra_info_dirty) | ||
274 | return true; | ||
275 | |||
276 | /* to set GO bit */ | ||
277 | if (op->shadow_extra_info_dirty) | ||
278 | return true; | ||
279 | |||
280 | if (!op->enabled) | ||
281 | continue; | ||
282 | |||
283 | /* to write new values to registers */ | ||
284 | if (op->info_dirty) | ||
285 | return true; | ||
286 | |||
287 | /* to set GO bit */ | ||
288 | if (op->shadow_info_dirty) | ||
289 | return true; | ||
290 | } | ||
291 | } | ||
292 | } | ||
293 | |||
294 | return false; | ||
295 | } | ||
296 | |||
297 | static bool need_go(struct omap_overlay_manager *mgr) | ||
298 | { | ||
299 | struct omap_overlay *ovl; | ||
300 | struct mgr_priv_data *mp; | ||
301 | struct ovl_priv_data *op; | ||
302 | |||
303 | mp = get_mgr_priv(mgr); | ||
304 | |||
305 | if (mp->shadow_info_dirty) | ||
306 | return true; | ||
307 | |||
308 | list_for_each_entry(ovl, &mgr->overlays, list) { | ||
309 | op = get_ovl_priv(ovl); | ||
310 | if (op->shadow_info_dirty || op->shadow_extra_info_dirty) | ||
311 | return true; | ||
312 | } | ||
313 | |||
314 | return false; | ||
315 | } | ||
316 | |||
317 | /* returns true if an extra_info field is currently being updated */ | ||
318 | static bool extra_info_update_ongoing(void) | ||
319 | { | ||
320 | const int num_ovls = omap_dss_get_num_overlays(); | ||
321 | struct ovl_priv_data *op; | ||
322 | struct omap_overlay *ovl; | ||
323 | struct mgr_priv_data *mp; | ||
324 | int i; | ||
325 | |||
326 | for (i = 0; i < num_ovls; ++i) { | ||
327 | ovl = omap_dss_get_overlay(i); | ||
328 | op = get_ovl_priv(ovl); | ||
329 | |||
330 | if (!ovl->manager) | ||
331 | continue; | ||
332 | |||
333 | mp = get_mgr_priv(ovl->manager); | ||
334 | |||
335 | if (!mp->enabled) | ||
336 | continue; | ||
337 | |||
338 | if (!mp->updating) | ||
339 | continue; | ||
340 | |||
341 | if (op->extra_info_dirty || op->shadow_extra_info_dirty) | ||
342 | return true; | ||
343 | } | ||
344 | |||
345 | return false; | ||
346 | } | ||
347 | |||
348 | /* wait until no extra_info updates are pending */ | ||
349 | static void wait_pending_extra_info_updates(void) | ||
350 | { | ||
351 | bool updating; | ||
352 | unsigned long flags; | ||
353 | unsigned long t; | ||
354 | |||
355 | spin_lock_irqsave(&data_lock, flags); | ||
356 | |||
357 | updating = extra_info_update_ongoing(); | ||
358 | |||
359 | if (!updating) { | ||
360 | spin_unlock_irqrestore(&data_lock, flags); | ||
361 | return; | ||
362 | } | ||
363 | |||
364 | init_completion(&extra_updated_completion); | ||
365 | |||
366 | spin_unlock_irqrestore(&data_lock, flags); | ||
367 | |||
368 | t = msecs_to_jiffies(500); | ||
369 | wait_for_completion_timeout(&extra_updated_completion, t); | ||
370 | |||
371 | updating = extra_info_update_ongoing(); | ||
372 | |||
373 | WARN_ON(updating); | ||
374 | } | ||
375 | |||
376 | int dss_mgr_wait_for_go(struct omap_overlay_manager *mgr) | ||
377 | { | ||
378 | unsigned long timeout = msecs_to_jiffies(500); | ||
379 | struct mgr_priv_data *mp; | ||
380 | u32 irq; | ||
381 | int r; | ||
382 | int i; | ||
383 | struct omap_dss_device *dssdev = mgr->device; | ||
384 | |||
385 | if (!dssdev || dssdev->state != OMAP_DSS_DISPLAY_ACTIVE) | ||
386 | return 0; | ||
387 | |||
388 | if (mgr_manual_update(mgr)) | ||
389 | return 0; | ||
390 | |||
391 | irq = dispc_mgr_get_vsync_irq(mgr->id); | ||
392 | |||
393 | mp = get_mgr_priv(mgr); | ||
394 | i = 0; | ||
395 | while (1) { | ||
396 | unsigned long flags; | ||
397 | bool shadow_dirty, dirty; | ||
398 | |||
399 | spin_lock_irqsave(&data_lock, flags); | ||
400 | dirty = mp->info_dirty; | ||
401 | shadow_dirty = mp->shadow_info_dirty; | ||
402 | spin_unlock_irqrestore(&data_lock, flags); | ||
403 | |||
404 | if (!dirty && !shadow_dirty) { | ||
405 | r = 0; | ||
406 | break; | ||
407 | } | ||
408 | |||
409 | /* 4 iterations is the worst case: | ||
410 | * 1 - initial iteration, dirty = true (between VFP and VSYNC) | ||
411 | * 2 - first VSYNC, dirty = true | ||
412 | * 3 - dirty = false, shadow_dirty = true | ||
413 | * 4 - shadow_dirty = false */ | ||
414 | if (i++ == 3) { | ||
415 | DSSERR("mgr(%d)->wait_for_go() not finishing\n", | ||
416 | mgr->id); | ||
417 | r = 0; | ||
418 | break; | ||
419 | } | ||
420 | |||
421 | r = omap_dispc_wait_for_irq_interruptible_timeout(irq, timeout); | ||
422 | if (r == -ERESTARTSYS) | ||
423 | break; | ||
424 | |||
425 | if (r) { | ||
426 | DSSERR("mgr(%d)->wait_for_go() timeout\n", mgr->id); | ||
427 | break; | ||
428 | } | ||
429 | } | ||
430 | |||
431 | return r; | ||
432 | } | ||
433 | |||
434 | int dss_mgr_wait_for_go_ovl(struct omap_overlay *ovl) | ||
435 | { | ||
436 | unsigned long timeout = msecs_to_jiffies(500); | ||
437 | struct ovl_priv_data *op; | ||
438 | struct omap_dss_device *dssdev; | ||
439 | u32 irq; | ||
440 | int r; | ||
441 | int i; | ||
442 | |||
443 | if (!ovl->manager) | ||
444 | return 0; | ||
445 | |||
446 | dssdev = ovl->manager->device; | ||
447 | |||
448 | if (!dssdev || dssdev->state != OMAP_DSS_DISPLAY_ACTIVE) | ||
449 | return 0; | ||
450 | |||
451 | if (ovl_manual_update(ovl)) | ||
452 | return 0; | ||
453 | |||
454 | irq = dispc_mgr_get_vsync_irq(ovl->manager->id); | ||
455 | |||
456 | op = get_ovl_priv(ovl); | ||
457 | i = 0; | ||
458 | while (1) { | ||
459 | unsigned long flags; | ||
460 | bool shadow_dirty, dirty; | ||
461 | |||
462 | spin_lock_irqsave(&data_lock, flags); | ||
463 | dirty = op->info_dirty; | ||
464 | shadow_dirty = op->shadow_info_dirty; | ||
465 | spin_unlock_irqrestore(&data_lock, flags); | ||
466 | |||
467 | if (!dirty && !shadow_dirty) { | ||
468 | r = 0; | ||
469 | break; | ||
470 | } | ||
471 | |||
472 | /* 4 iterations is the worst case: | ||
473 | * 1 - initial iteration, dirty = true (between VFP and VSYNC) | ||
474 | * 2 - first VSYNC, dirty = true | ||
475 | * 3 - dirty = false, shadow_dirty = true | ||
476 | * 4 - shadow_dirty = false */ | ||
477 | if (i++ == 3) { | ||
478 | DSSERR("ovl(%d)->wait_for_go() not finishing\n", | ||
479 | ovl->id); | ||
480 | r = 0; | ||
481 | break; | ||
482 | } | ||
483 | |||
484 | r = omap_dispc_wait_for_irq_interruptible_timeout(irq, timeout); | ||
485 | if (r == -ERESTARTSYS) | ||
486 | break; | ||
487 | |||
488 | if (r) { | ||
489 | DSSERR("ovl(%d)->wait_for_go() timeout\n", ovl->id); | ||
490 | break; | ||
491 | } | ||
492 | } | ||
493 | |||
494 | return r; | ||
495 | } | ||
496 | |||
497 | static void dss_ovl_write_regs(struct omap_overlay *ovl) | ||
498 | { | ||
499 | struct ovl_priv_data *op = get_ovl_priv(ovl); | ||
500 | struct omap_overlay_info *oi; | ||
501 | bool ilace, replication; | ||
502 | struct mgr_priv_data *mp; | ||
503 | int r; | ||
504 | |||
505 | DSSDBGF("%d", ovl->id); | ||
506 | |||
507 | if (!op->enabled || !op->info_dirty) | ||
508 | return; | ||
509 | |||
510 | oi = &op->info; | ||
511 | |||
512 | replication = dss_use_replication(ovl->manager->device, oi->color_mode); | ||
513 | |||
514 | ilace = ovl->manager->device->type == OMAP_DISPLAY_TYPE_VENC; | ||
515 | |||
516 | r = dispc_ovl_setup(ovl->id, oi, ilace, replication); | ||
517 | if (r) { | ||
518 | /* | ||
519 | * We can't do much here, as this function can be called from | ||
520 | * vsync interrupt. | ||
521 | */ | ||
522 | DSSERR("dispc_ovl_setup failed for ovl %d\n", ovl->id); | ||
523 | |||
524 | /* This will leave fifo configurations in a nonoptimal state */ | ||
525 | op->enabled = false; | ||
526 | dispc_ovl_enable(ovl->id, false); | ||
527 | return; | ||
528 | } | ||
529 | |||
530 | mp = get_mgr_priv(ovl->manager); | ||
531 | |||
532 | op->info_dirty = false; | ||
533 | if (mp->updating) | ||
534 | op->shadow_info_dirty = true; | ||
535 | } | ||
536 | |||
537 | static void dss_ovl_write_regs_extra(struct omap_overlay *ovl) | ||
538 | { | ||
539 | struct ovl_priv_data *op = get_ovl_priv(ovl); | ||
540 | struct mgr_priv_data *mp; | ||
541 | |||
542 | DSSDBGF("%d", ovl->id); | ||
543 | |||
544 | if (!op->extra_info_dirty) | ||
545 | return; | ||
546 | |||
547 | /* note: write also when op->enabled == false, so that the ovl gets | ||
548 | * disabled */ | ||
549 | |||
550 | dispc_ovl_enable(ovl->id, op->enabled); | ||
551 | dispc_ovl_set_channel_out(ovl->id, op->channel); | ||
552 | dispc_ovl_set_fifo_threshold(ovl->id, op->fifo_low, op->fifo_high); | ||
553 | |||
554 | mp = get_mgr_priv(ovl->manager); | ||
555 | |||
556 | op->extra_info_dirty = false; | ||
557 | if (mp->updating) | ||
558 | op->shadow_extra_info_dirty = true; | ||
559 | } | ||
560 | |||
561 | static void dss_mgr_write_regs(struct omap_overlay_manager *mgr) | ||
562 | { | ||
563 | struct mgr_priv_data *mp = get_mgr_priv(mgr); | ||
564 | struct omap_overlay *ovl; | ||
565 | |||
566 | DSSDBGF("%d", mgr->id); | ||
567 | |||
568 | if (!mp->enabled) | ||
569 | return; | ||
570 | |||
571 | WARN_ON(mp->busy); | ||
572 | |||
573 | /* Commit overlay settings */ | ||
574 | list_for_each_entry(ovl, &mgr->overlays, list) { | ||
575 | dss_ovl_write_regs(ovl); | ||
576 | dss_ovl_write_regs_extra(ovl); | ||
577 | } | ||
578 | |||
579 | if (mp->info_dirty) { | ||
580 | dispc_mgr_setup(mgr->id, &mp->info); | ||
581 | |||
582 | mp->info_dirty = false; | ||
583 | if (mp->updating) | ||
584 | mp->shadow_info_dirty = true; | ||
585 | } | ||
586 | } | ||
587 | |||
588 | static void dss_write_regs(void) | ||
589 | { | ||
590 | const int num_mgrs = omap_dss_get_num_overlay_managers(); | ||
591 | int i; | ||
592 | |||
593 | for (i = 0; i < num_mgrs; ++i) { | ||
594 | struct omap_overlay_manager *mgr; | ||
595 | struct mgr_priv_data *mp; | ||
596 | int r; | ||
597 | |||
598 | mgr = omap_dss_get_overlay_manager(i); | ||
599 | mp = get_mgr_priv(mgr); | ||
600 | |||
601 | if (!mp->enabled || mgr_manual_update(mgr) || mp->busy) | ||
602 | continue; | ||
603 | |||
604 | r = dss_check_settings(mgr, mgr->device); | ||
605 | if (r) { | ||
606 | DSSERR("cannot write registers for manager %s: " | ||
607 | "illegal configuration\n", mgr->name); | ||
608 | continue; | ||
609 | } | ||
610 | |||
611 | dss_mgr_write_regs(mgr); | ||
612 | } | ||
613 | } | ||
614 | |||
615 | static void dss_set_go_bits(void) | ||
616 | { | ||
617 | const int num_mgrs = omap_dss_get_num_overlay_managers(); | ||
618 | int i; | ||
619 | |||
620 | for (i = 0; i < num_mgrs; ++i) { | ||
621 | struct omap_overlay_manager *mgr; | ||
622 | struct mgr_priv_data *mp; | ||
623 | |||
624 | mgr = omap_dss_get_overlay_manager(i); | ||
625 | mp = get_mgr_priv(mgr); | ||
626 | |||
627 | if (!mp->enabled || mgr_manual_update(mgr) || mp->busy) | ||
628 | continue; | ||
629 | |||
630 | if (!need_go(mgr)) | ||
631 | continue; | ||
632 | |||
633 | mp->busy = true; | ||
634 | |||
635 | if (!dss_data.irq_enabled && need_isr()) | ||
636 | dss_register_vsync_isr(); | ||
637 | |||
638 | dispc_mgr_go(mgr->id); | ||
639 | } | ||
640 | |||
641 | } | ||
642 | |||
643 | void dss_mgr_start_update(struct omap_overlay_manager *mgr) | ||
644 | { | ||
645 | struct mgr_priv_data *mp = get_mgr_priv(mgr); | ||
646 | unsigned long flags; | ||
647 | int r; | ||
648 | |||
649 | spin_lock_irqsave(&data_lock, flags); | ||
650 | |||
651 | WARN_ON(mp->updating); | ||
652 | |||
653 | r = dss_check_settings(mgr, mgr->device); | ||
654 | if (r) { | ||
655 | DSSERR("cannot start manual update: illegal configuration\n"); | ||
656 | spin_unlock_irqrestore(&data_lock, flags); | ||
657 | return; | ||
658 | } | ||
659 | |||
660 | dss_mgr_write_regs(mgr); | ||
661 | |||
662 | mp->updating = true; | ||
663 | |||
664 | if (!dss_data.irq_enabled && need_isr()) | ||
665 | dss_register_vsync_isr(); | ||
666 | |||
667 | dispc_mgr_enable(mgr->id, true); | ||
668 | |||
669 | spin_unlock_irqrestore(&data_lock, flags); | ||
670 | } | ||
671 | |||
672 | static void dss_apply_irq_handler(void *data, u32 mask); | ||
673 | |||
674 | static void dss_register_vsync_isr(void) | ||
675 | { | ||
676 | const int num_mgrs = dss_feat_get_num_mgrs(); | ||
677 | u32 mask; | ||
678 | int r, i; | ||
679 | |||
680 | mask = 0; | ||
681 | for (i = 0; i < num_mgrs; ++i) | ||
682 | mask |= dispc_mgr_get_vsync_irq(i); | ||
683 | |||
684 | for (i = 0; i < num_mgrs; ++i) | ||
685 | mask |= dispc_mgr_get_framedone_irq(i); | ||
686 | |||
687 | r = omap_dispc_register_isr(dss_apply_irq_handler, NULL, mask); | ||
688 | WARN_ON(r); | ||
689 | |||
690 | dss_data.irq_enabled = true; | ||
691 | } | ||
692 | |||
693 | static void dss_unregister_vsync_isr(void) | ||
694 | { | ||
695 | const int num_mgrs = dss_feat_get_num_mgrs(); | ||
696 | u32 mask; | ||
697 | int r, i; | ||
698 | |||
699 | mask = 0; | ||
700 | for (i = 0; i < num_mgrs; ++i) | ||
701 | mask |= dispc_mgr_get_vsync_irq(i); | ||
702 | |||
703 | for (i = 0; i < num_mgrs; ++i) | ||
704 | mask |= dispc_mgr_get_framedone_irq(i); | ||
705 | |||
706 | r = omap_dispc_unregister_isr(dss_apply_irq_handler, NULL, mask); | ||
707 | WARN_ON(r); | ||
708 | |||
709 | dss_data.irq_enabled = false; | ||
710 | } | ||
711 | |||
712 | static void mgr_clear_shadow_dirty(struct omap_overlay_manager *mgr) | ||
713 | { | ||
714 | struct omap_overlay *ovl; | ||
715 | struct mgr_priv_data *mp; | ||
716 | struct ovl_priv_data *op; | ||
717 | |||
718 | mp = get_mgr_priv(mgr); | ||
719 | mp->shadow_info_dirty = false; | ||
720 | |||
721 | list_for_each_entry(ovl, &mgr->overlays, list) { | ||
722 | op = get_ovl_priv(ovl); | ||
723 | op->shadow_info_dirty = false; | ||
724 | op->shadow_extra_info_dirty = false; | ||
725 | } | ||
726 | } | ||
727 | |||
728 | static void dss_apply_irq_handler(void *data, u32 mask) | ||
729 | { | ||
730 | const int num_mgrs = dss_feat_get_num_mgrs(); | ||
731 | int i; | ||
732 | bool extra_updating; | ||
733 | |||
734 | spin_lock(&data_lock); | ||
735 | |||
736 | /* clear busy, updating flags, shadow_dirty flags */ | ||
737 | for (i = 0; i < num_mgrs; i++) { | ||
738 | struct omap_overlay_manager *mgr; | ||
739 | struct mgr_priv_data *mp; | ||
740 | bool was_updating; | ||
741 | |||
742 | mgr = omap_dss_get_overlay_manager(i); | ||
743 | mp = get_mgr_priv(mgr); | ||
744 | |||
745 | if (!mp->enabled) | ||
746 | continue; | ||
747 | |||
748 | was_updating = mp->updating; | ||
749 | mp->updating = dispc_mgr_is_enabled(i); | ||
750 | |||
751 | if (!mgr_manual_update(mgr)) { | ||
752 | bool was_busy = mp->busy; | ||
753 | mp->busy = dispc_mgr_go_busy(i); | ||
754 | |||
755 | if (was_busy && !mp->busy) | ||
756 | mgr_clear_shadow_dirty(mgr); | ||
757 | } else { | ||
758 | if (was_updating && !mp->updating) | ||
759 | mgr_clear_shadow_dirty(mgr); | ||
760 | } | ||
761 | } | ||
762 | |||
763 | dss_write_regs(); | ||
764 | dss_set_go_bits(); | ||
765 | |||
766 | extra_updating = extra_info_update_ongoing(); | ||
767 | if (!extra_updating) | ||
768 | complete_all(&extra_updated_completion); | ||
769 | |||
770 | if (!need_isr()) | ||
771 | dss_unregister_vsync_isr(); | ||
772 | |||
773 | spin_unlock(&data_lock); | ||
774 | } | ||
775 | |||
776 | static void omap_dss_mgr_apply_ovl(struct omap_overlay *ovl) | ||
777 | { | ||
778 | struct ovl_priv_data *op; | ||
779 | |||
780 | op = get_ovl_priv(ovl); | ||
781 | |||
782 | if (!op->user_info_dirty) | ||
783 | return; | ||
784 | |||
785 | op->user_info_dirty = false; | ||
786 | op->info_dirty = true; | ||
787 | op->info = op->user_info; | ||
788 | } | ||
789 | |||
790 | static void omap_dss_mgr_apply_mgr(struct omap_overlay_manager *mgr) | ||
791 | { | ||
792 | struct mgr_priv_data *mp; | ||
793 | |||
794 | mp = get_mgr_priv(mgr); | ||
795 | |||
796 | if (!mp->user_info_dirty) | ||
797 | return; | ||
798 | |||
799 | mp->user_info_dirty = false; | ||
800 | mp->info_dirty = true; | ||
801 | mp->info = mp->user_info; | ||
802 | } | ||
803 | |||
804 | int omap_dss_mgr_apply(struct omap_overlay_manager *mgr) | ||
805 | { | ||
806 | unsigned long flags; | ||
807 | struct omap_overlay *ovl; | ||
808 | int r; | ||
809 | |||
810 | DSSDBG("omap_dss_mgr_apply(%s)\n", mgr->name); | ||
811 | |||
812 | spin_lock_irqsave(&data_lock, flags); | ||
813 | |||
814 | r = dss_check_settings_apply(mgr, mgr->device); | ||
815 | if (r) { | ||
816 | spin_unlock_irqrestore(&data_lock, flags); | ||
817 | DSSERR("failed to apply settings: illegal configuration.\n"); | ||
818 | return r; | ||
819 | } | ||
820 | |||
821 | /* Configure overlays */ | ||
822 | list_for_each_entry(ovl, &mgr->overlays, list) | ||
823 | omap_dss_mgr_apply_ovl(ovl); | ||
824 | |||
825 | /* Configure manager */ | ||
826 | omap_dss_mgr_apply_mgr(mgr); | ||
827 | |||
828 | dss_write_regs(); | ||
829 | dss_set_go_bits(); | ||
830 | |||
831 | spin_unlock_irqrestore(&data_lock, flags); | ||
832 | |||
833 | return 0; | ||
834 | } | ||
835 | |||
836 | static void dss_apply_ovl_enable(struct omap_overlay *ovl, bool enable) | ||
837 | { | ||
838 | struct ovl_priv_data *op; | ||
839 | |||
840 | op = get_ovl_priv(ovl); | ||
841 | |||
842 | if (op->enabled == enable) | ||
843 | return; | ||
844 | |||
845 | op->enabled = enable; | ||
846 | op->extra_info_dirty = true; | ||
847 | } | ||
848 | |||
849 | static void dss_apply_ovl_fifo_thresholds(struct omap_overlay *ovl, | ||
850 | u32 fifo_low, u32 fifo_high) | ||
851 | { | ||
852 | struct ovl_priv_data *op = get_ovl_priv(ovl); | ||
853 | |||
854 | if (op->fifo_low == fifo_low && op->fifo_high == fifo_high) | ||
855 | return; | ||
856 | |||
857 | op->fifo_low = fifo_low; | ||
858 | op->fifo_high = fifo_high; | ||
859 | op->extra_info_dirty = true; | ||
860 | } | ||
861 | |||
862 | static void dss_ovl_setup_fifo(struct omap_overlay *ovl) | ||
863 | { | ||
864 | struct ovl_priv_data *op = get_ovl_priv(ovl); | ||
865 | struct omap_dss_device *dssdev; | ||
866 | u32 size, burst_size; | ||
867 | u32 fifo_low, fifo_high; | ||
868 | |||
869 | if (!op->enabled && !op->enabling) | ||
870 | return; | ||
871 | |||
872 | dssdev = ovl->manager->device; | ||
873 | |||
874 | size = dispc_ovl_get_fifo_size(ovl->id); | ||
875 | |||
876 | burst_size = dispc_ovl_get_burst_size(ovl->id); | ||
877 | |||
878 | switch (dssdev->type) { | ||
879 | case OMAP_DISPLAY_TYPE_DPI: | ||
880 | case OMAP_DISPLAY_TYPE_DBI: | ||
881 | case OMAP_DISPLAY_TYPE_SDI: | ||
882 | case OMAP_DISPLAY_TYPE_VENC: | ||
883 | case OMAP_DISPLAY_TYPE_HDMI: | ||
884 | default_get_overlay_fifo_thresholds(ovl->id, size, | ||
885 | burst_size, &fifo_low, &fifo_high); | ||
886 | break; | ||
887 | #ifdef CONFIG_OMAP2_DSS_DSI | ||
888 | case OMAP_DISPLAY_TYPE_DSI: | ||
889 | dsi_get_overlay_fifo_thresholds(ovl->id, size, | ||
890 | burst_size, &fifo_low, &fifo_high); | ||
891 | break; | ||
892 | #endif | ||
893 | default: | ||
894 | BUG(); | ||
895 | } | ||
896 | |||
897 | dss_apply_ovl_fifo_thresholds(ovl, fifo_low, fifo_high); | ||
898 | } | ||
899 | |||
900 | static void dss_mgr_setup_fifos(struct omap_overlay_manager *mgr) | ||
901 | { | ||
902 | struct omap_overlay *ovl; | ||
903 | struct mgr_priv_data *mp; | ||
904 | |||
905 | mp = get_mgr_priv(mgr); | ||
906 | |||
907 | if (!mp->enabled) | ||
908 | return; | ||
909 | |||
910 | list_for_each_entry(ovl, &mgr->overlays, list) | ||
911 | dss_ovl_setup_fifo(ovl); | ||
912 | } | ||
913 | |||
914 | static void dss_setup_fifos(void) | ||
915 | { | ||
916 | const int num_mgrs = omap_dss_get_num_overlay_managers(); | ||
917 | struct omap_overlay_manager *mgr; | ||
918 | int i; | ||
919 | |||
920 | for (i = 0; i < num_mgrs; ++i) { | ||
921 | mgr = omap_dss_get_overlay_manager(i); | ||
922 | dss_mgr_setup_fifos(mgr); | ||
923 | } | ||
924 | } | ||
925 | |||
926 | int dss_mgr_enable(struct omap_overlay_manager *mgr) | ||
927 | { | ||
928 | struct mgr_priv_data *mp = get_mgr_priv(mgr); | ||
929 | unsigned long flags; | ||
930 | int r; | ||
931 | |||
932 | mutex_lock(&apply_lock); | ||
933 | |||
934 | if (mp->enabled) | ||
935 | goto out; | ||
936 | |||
937 | spin_lock_irqsave(&data_lock, flags); | ||
938 | |||
939 | mp->enabled = true; | ||
940 | |||
941 | r = dss_check_settings(mgr, mgr->device); | ||
942 | if (r) { | ||
943 | DSSERR("failed to enable manager %d: check_settings failed\n", | ||
944 | mgr->id); | ||
945 | goto err; | ||
946 | } | ||
947 | |||
948 | dss_setup_fifos(); | ||
949 | |||
950 | dss_write_regs(); | ||
951 | dss_set_go_bits(); | ||
952 | |||
953 | if (!mgr_manual_update(mgr)) | ||
954 | mp->updating = true; | ||
955 | |||
956 | spin_unlock_irqrestore(&data_lock, flags); | ||
957 | |||
958 | if (!mgr_manual_update(mgr)) | ||
959 | dispc_mgr_enable(mgr->id, true); | ||
960 | |||
961 | out: | ||
962 | mutex_unlock(&apply_lock); | ||
963 | |||
964 | return 0; | ||
965 | |||
966 | err: | ||
967 | mp->enabled = false; | ||
968 | spin_unlock_irqrestore(&data_lock, flags); | ||
969 | mutex_unlock(&apply_lock); | ||
970 | return r; | ||
971 | } | ||
972 | |||
973 | void dss_mgr_disable(struct omap_overlay_manager *mgr) | ||
974 | { | ||
975 | struct mgr_priv_data *mp = get_mgr_priv(mgr); | ||
976 | unsigned long flags; | ||
977 | |||
978 | mutex_lock(&apply_lock); | ||
979 | |||
980 | if (!mp->enabled) | ||
981 | goto out; | ||
982 | |||
983 | if (!mgr_manual_update(mgr)) | ||
984 | dispc_mgr_enable(mgr->id, false); | ||
985 | |||
986 | spin_lock_irqsave(&data_lock, flags); | ||
987 | |||
988 | mp->updating = false; | ||
989 | mp->enabled = false; | ||
990 | |||
991 | spin_unlock_irqrestore(&data_lock, flags); | ||
992 | |||
993 | out: | ||
994 | mutex_unlock(&apply_lock); | ||
995 | } | ||
996 | |||
997 | int dss_mgr_set_info(struct omap_overlay_manager *mgr, | ||
998 | struct omap_overlay_manager_info *info) | ||
999 | { | ||
1000 | struct mgr_priv_data *mp = get_mgr_priv(mgr); | ||
1001 | unsigned long flags; | ||
1002 | int r; | ||
1003 | |||
1004 | r = dss_mgr_simple_check(mgr, info); | ||
1005 | if (r) | ||
1006 | return r; | ||
1007 | |||
1008 | spin_lock_irqsave(&data_lock, flags); | ||
1009 | |||
1010 | mp->user_info = *info; | ||
1011 | mp->user_info_dirty = true; | ||
1012 | |||
1013 | spin_unlock_irqrestore(&data_lock, flags); | ||
1014 | |||
1015 | return 0; | ||
1016 | } | ||
1017 | |||
1018 | void dss_mgr_get_info(struct omap_overlay_manager *mgr, | ||
1019 | struct omap_overlay_manager_info *info) | ||
1020 | { | ||
1021 | struct mgr_priv_data *mp = get_mgr_priv(mgr); | ||
1022 | unsigned long flags; | ||
1023 | |||
1024 | spin_lock_irqsave(&data_lock, flags); | ||
1025 | |||
1026 | *info = mp->user_info; | ||
1027 | |||
1028 | spin_unlock_irqrestore(&data_lock, flags); | ||
1029 | } | ||
1030 | |||
1031 | int dss_mgr_set_device(struct omap_overlay_manager *mgr, | ||
1032 | struct omap_dss_device *dssdev) | ||
1033 | { | ||
1034 | int r; | ||
1035 | |||
1036 | mutex_lock(&apply_lock); | ||
1037 | |||
1038 | if (dssdev->manager) { | ||
1039 | DSSERR("display '%s' already has a manager '%s'\n", | ||
1040 | dssdev->name, dssdev->manager->name); | ||
1041 | r = -EINVAL; | ||
1042 | goto err; | ||
1043 | } | ||
1044 | |||
1045 | if ((mgr->supported_displays & dssdev->type) == 0) { | ||
1046 | DSSERR("display '%s' does not support manager '%s'\n", | ||
1047 | dssdev->name, mgr->name); | ||
1048 | r = -EINVAL; | ||
1049 | goto err; | ||
1050 | } | ||
1051 | |||
1052 | dssdev->manager = mgr; | ||
1053 | mgr->device = dssdev; | ||
1054 | |||
1055 | mutex_unlock(&apply_lock); | ||
1056 | |||
1057 | return 0; | ||
1058 | err: | ||
1059 | mutex_unlock(&apply_lock); | ||
1060 | return r; | ||
1061 | } | ||
1062 | |||
1063 | int dss_mgr_unset_device(struct omap_overlay_manager *mgr) | ||
1064 | { | ||
1065 | int r; | ||
1066 | |||
1067 | mutex_lock(&apply_lock); | ||
1068 | |||
1069 | if (!mgr->device) { | ||
1070 | DSSERR("failed to unset display, display not set.\n"); | ||
1071 | r = -EINVAL; | ||
1072 | goto err; | ||
1073 | } | ||
1074 | |||
1075 | /* | ||
1076 | * Don't allow currently enabled displays to have the overlay manager | ||
1077 | * pulled out from underneath them | ||
1078 | */ | ||
1079 | if (mgr->device->state != OMAP_DSS_DISPLAY_DISABLED) { | ||
1080 | r = -EINVAL; | ||
1081 | goto err; | ||
1082 | } | ||
1083 | |||
1084 | mgr->device->manager = NULL; | ||
1085 | mgr->device = NULL; | ||
1086 | |||
1087 | mutex_unlock(&apply_lock); | ||
1088 | |||
1089 | return 0; | ||
1090 | err: | ||
1091 | mutex_unlock(&apply_lock); | ||
1092 | return r; | ||
1093 | } | ||
1094 | |||
1095 | |||
1096 | int dss_ovl_set_info(struct omap_overlay *ovl, | ||
1097 | struct omap_overlay_info *info) | ||
1098 | { | ||
1099 | struct ovl_priv_data *op = get_ovl_priv(ovl); | ||
1100 | unsigned long flags; | ||
1101 | int r; | ||
1102 | |||
1103 | r = dss_ovl_simple_check(ovl, info); | ||
1104 | if (r) | ||
1105 | return r; | ||
1106 | |||
1107 | spin_lock_irqsave(&data_lock, flags); | ||
1108 | |||
1109 | op->user_info = *info; | ||
1110 | op->user_info_dirty = true; | ||
1111 | |||
1112 | spin_unlock_irqrestore(&data_lock, flags); | ||
1113 | |||
1114 | return 0; | ||
1115 | } | ||
1116 | |||
1117 | void dss_ovl_get_info(struct omap_overlay *ovl, | ||
1118 | struct omap_overlay_info *info) | ||
1119 | { | ||
1120 | struct ovl_priv_data *op = get_ovl_priv(ovl); | ||
1121 | unsigned long flags; | ||
1122 | |||
1123 | spin_lock_irqsave(&data_lock, flags); | ||
1124 | |||
1125 | *info = op->user_info; | ||
1126 | |||
1127 | spin_unlock_irqrestore(&data_lock, flags); | ||
1128 | } | ||
1129 | |||
1130 | int dss_ovl_set_manager(struct omap_overlay *ovl, | ||
1131 | struct omap_overlay_manager *mgr) | ||
1132 | { | ||
1133 | struct ovl_priv_data *op = get_ovl_priv(ovl); | ||
1134 | unsigned long flags; | ||
1135 | int r; | ||
1136 | |||
1137 | if (!mgr) | ||
1138 | return -EINVAL; | ||
1139 | |||
1140 | mutex_lock(&apply_lock); | ||
1141 | |||
1142 | if (ovl->manager) { | ||
1143 | DSSERR("overlay '%s' already has a manager '%s'\n", | ||
1144 | ovl->name, ovl->manager->name); | ||
1145 | r = -EINVAL; | ||
1146 | goto err; | ||
1147 | } | ||
1148 | |||
1149 | spin_lock_irqsave(&data_lock, flags); | ||
1150 | |||
1151 | if (op->enabled) { | ||
1152 | spin_unlock_irqrestore(&data_lock, flags); | ||
1153 | DSSERR("overlay has to be disabled to change the manager\n"); | ||
1154 | r = -EINVAL; | ||
1155 | goto err; | ||
1156 | } | ||
1157 | |||
1158 | op->channel = mgr->id; | ||
1159 | op->extra_info_dirty = true; | ||
1160 | |||
1161 | ovl->manager = mgr; | ||
1162 | list_add_tail(&ovl->list, &mgr->overlays); | ||
1163 | |||
1164 | spin_unlock_irqrestore(&data_lock, flags); | ||
1165 | |||
1166 | /* XXX: When there is an overlay on a DSI manual update display, and | ||
1167 | * the overlay is first disabled, then moved to tv, and enabled, we | ||
1168 | * seem to get SYNC_LOST_DIGIT error. | ||
1169 | * | ||
1170 | * Waiting doesn't seem to help, but updating the manual update display | ||
1171 | * after disabling the overlay seems to fix this. This hints that the | ||
1172 | * overlay is perhaps somehow tied to the LCD output until the output | ||
1173 | * is updated. | ||
1174 | * | ||
1175 | * Userspace workaround for this is to update the LCD after disabling | ||
1176 | * the overlay, but before moving the overlay to TV. | ||
1177 | */ | ||
1178 | |||
1179 | mutex_unlock(&apply_lock); | ||
1180 | |||
1181 | return 0; | ||
1182 | err: | ||
1183 | mutex_unlock(&apply_lock); | ||
1184 | return r; | ||
1185 | } | ||
1186 | |||
1187 | int dss_ovl_unset_manager(struct omap_overlay *ovl) | ||
1188 | { | ||
1189 | struct ovl_priv_data *op = get_ovl_priv(ovl); | ||
1190 | unsigned long flags; | ||
1191 | int r; | ||
1192 | |||
1193 | mutex_lock(&apply_lock); | ||
1194 | |||
1195 | if (!ovl->manager) { | ||
1196 | DSSERR("failed to detach overlay: manager not set\n"); | ||
1197 | r = -EINVAL; | ||
1198 | goto err; | ||
1199 | } | ||
1200 | |||
1201 | spin_lock_irqsave(&data_lock, flags); | ||
1202 | |||
1203 | if (op->enabled) { | ||
1204 | spin_unlock_irqrestore(&data_lock, flags); | ||
1205 | DSSERR("overlay has to be disabled to unset the manager\n"); | ||
1206 | r = -EINVAL; | ||
1207 | goto err; | ||
1208 | } | ||
1209 | |||
1210 | op->channel = -1; | ||
1211 | |||
1212 | ovl->manager = NULL; | ||
1213 | list_del(&ovl->list); | ||
1214 | |||
1215 | spin_unlock_irqrestore(&data_lock, flags); | ||
1216 | |||
1217 | mutex_unlock(&apply_lock); | ||
1218 | |||
1219 | return 0; | ||
1220 | err: | ||
1221 | mutex_unlock(&apply_lock); | ||
1222 | return r; | ||
1223 | } | ||
1224 | |||
1225 | bool dss_ovl_is_enabled(struct omap_overlay *ovl) | ||
1226 | { | ||
1227 | struct ovl_priv_data *op = get_ovl_priv(ovl); | ||
1228 | unsigned long flags; | ||
1229 | bool e; | ||
1230 | |||
1231 | spin_lock_irqsave(&data_lock, flags); | ||
1232 | |||
1233 | e = op->enabled; | ||
1234 | |||
1235 | spin_unlock_irqrestore(&data_lock, flags); | ||
1236 | |||
1237 | return e; | ||
1238 | } | ||
1239 | |||
1240 | int dss_ovl_enable(struct omap_overlay *ovl) | ||
1241 | { | ||
1242 | struct ovl_priv_data *op = get_ovl_priv(ovl); | ||
1243 | unsigned long flags; | ||
1244 | int r; | ||
1245 | |||
1246 | mutex_lock(&apply_lock); | ||
1247 | |||
1248 | if (op->enabled) { | ||
1249 | r = 0; | ||
1250 | goto err1; | ||
1251 | } | ||
1252 | |||
1253 | if (ovl->manager == NULL || ovl->manager->device == NULL) { | ||
1254 | r = -EINVAL; | ||
1255 | goto err1; | ||
1256 | } | ||
1257 | |||
1258 | spin_lock_irqsave(&data_lock, flags); | ||
1259 | |||
1260 | op->enabling = true; | ||
1261 | |||
1262 | r = dss_check_settings(ovl->manager, ovl->manager->device); | ||
1263 | if (r) { | ||
1264 | DSSERR("failed to enable overlay %d: check_settings failed\n", | ||
1265 | ovl->id); | ||
1266 | goto err2; | ||
1267 | } | ||
1268 | |||
1269 | dss_setup_fifos(); | ||
1270 | |||
1271 | op->enabling = false; | ||
1272 | dss_apply_ovl_enable(ovl, true); | ||
1273 | |||
1274 | dss_write_regs(); | ||
1275 | dss_set_go_bits(); | ||
1276 | |||
1277 | spin_unlock_irqrestore(&data_lock, flags); | ||
1278 | |||
1279 | mutex_unlock(&apply_lock); | ||
1280 | |||
1281 | return 0; | ||
1282 | err2: | ||
1283 | op->enabling = false; | ||
1284 | spin_unlock_irqrestore(&data_lock, flags); | ||
1285 | err1: | ||
1286 | mutex_unlock(&apply_lock); | ||
1287 | return r; | ||
1288 | } | ||
1289 | |||
1290 | int dss_ovl_disable(struct omap_overlay *ovl) | ||
1291 | { | ||
1292 | struct ovl_priv_data *op = get_ovl_priv(ovl); | ||
1293 | unsigned long flags; | ||
1294 | int r; | ||
1295 | |||
1296 | mutex_lock(&apply_lock); | ||
1297 | |||
1298 | if (!op->enabled) { | ||
1299 | r = 0; | ||
1300 | goto err; | ||
1301 | } | ||
1302 | |||
1303 | if (ovl->manager == NULL || ovl->manager->device == NULL) { | ||
1304 | r = -EINVAL; | ||
1305 | goto err; | ||
1306 | } | ||
1307 | |||
1308 | spin_lock_irqsave(&data_lock, flags); | ||
1309 | |||
1310 | dss_apply_ovl_enable(ovl, false); | ||
1311 | dss_write_regs(); | ||
1312 | dss_set_go_bits(); | ||
1313 | |||
1314 | spin_unlock_irqrestore(&data_lock, flags); | ||
1315 | |||
1316 | mutex_unlock(&apply_lock); | ||
1317 | |||
1318 | return 0; | ||
1319 | |||
1320 | err: | ||
1321 | mutex_unlock(&apply_lock); | ||
1322 | return r; | ||
1323 | } | ||
1324 | |||
diff --git a/drivers/video/omap2/dss/core.c b/drivers/video/omap2/dss/core.c index da7b18576549..8613f86fb56d 100644 --- a/drivers/video/omap2/dss/core.c +++ b/drivers/video/omap2/dss/core.c | |||
@@ -178,6 +178,8 @@ static int omap_dss_probe(struct platform_device *pdev) | |||
178 | 178 | ||
179 | dss_features_init(); | 179 | dss_features_init(); |
180 | 180 | ||
181 | dss_apply_init(); | ||
182 | |||
181 | dss_init_overlay_managers(pdev); | 183 | dss_init_overlay_managers(pdev); |
182 | dss_init_overlays(pdev); | 184 | dss_init_overlays(pdev); |
183 | 185 | ||
diff --git a/drivers/video/omap2/dss/dispc.c b/drivers/video/omap2/dss/dispc.c index 5c81533eacaa..a5ec7f37c185 100644 --- a/drivers/video/omap2/dss/dispc.c +++ b/drivers/video/omap2/dss/dispc.c | |||
@@ -64,22 +64,6 @@ struct omap_dispc_isr_data { | |||
64 | u32 mask; | 64 | u32 mask; |
65 | }; | 65 | }; |
66 | 66 | ||
67 | struct dispc_h_coef { | ||
68 | s8 hc4; | ||
69 | s8 hc3; | ||
70 | u8 hc2; | ||
71 | s8 hc1; | ||
72 | s8 hc0; | ||
73 | }; | ||
74 | |||
75 | struct dispc_v_coef { | ||
76 | s8 vc22; | ||
77 | s8 vc2; | ||
78 | u8 vc1; | ||
79 | s8 vc0; | ||
80 | s8 vc00; | ||
81 | }; | ||
82 | |||
83 | enum omap_burst_size { | 67 | enum omap_burst_size { |
84 | BURST_SIZE_X2 = 0, | 68 | BURST_SIZE_X2 = 0, |
85 | BURST_SIZE_X4 = 1, | 69 | BURST_SIZE_X4 = 1, |
@@ -438,6 +422,34 @@ static struct omap_dss_device *dispc_mgr_get_device(enum omap_channel channel) | |||
438 | return mgr ? mgr->device : NULL; | 422 | return mgr ? mgr->device : NULL; |
439 | } | 423 | } |
440 | 424 | ||
425 | u32 dispc_mgr_get_vsync_irq(enum omap_channel channel) | ||
426 | { | ||
427 | switch (channel) { | ||
428 | case OMAP_DSS_CHANNEL_LCD: | ||
429 | return DISPC_IRQ_VSYNC; | ||
430 | case OMAP_DSS_CHANNEL_LCD2: | ||
431 | return DISPC_IRQ_VSYNC2; | ||
432 | case OMAP_DSS_CHANNEL_DIGIT: | ||
433 | return DISPC_IRQ_EVSYNC_ODD | DISPC_IRQ_EVSYNC_EVEN; | ||
434 | default: | ||
435 | BUG(); | ||
436 | } | ||
437 | } | ||
438 | |||
439 | u32 dispc_mgr_get_framedone_irq(enum omap_channel channel) | ||
440 | { | ||
441 | switch (channel) { | ||
442 | case OMAP_DSS_CHANNEL_LCD: | ||
443 | return DISPC_IRQ_FRAMEDONE; | ||
444 | case OMAP_DSS_CHANNEL_LCD2: | ||
445 | return DISPC_IRQ_FRAMEDONE2; | ||
446 | case OMAP_DSS_CHANNEL_DIGIT: | ||
447 | return 0; | ||
448 | default: | ||
449 | BUG(); | ||
450 | } | ||
451 | } | ||
452 | |||
441 | bool dispc_mgr_go_busy(enum omap_channel channel) | 453 | bool dispc_mgr_go_busy(enum omap_channel channel) |
442 | { | 454 | { |
443 | int bit; | 455 | int bit; |
@@ -533,105 +545,27 @@ static void dispc_ovl_write_firv2_reg(enum omap_plane plane, int reg, u32 value) | |||
533 | dispc_write_reg(DISPC_OVL_FIR_COEF_V2(plane, reg), value); | 545 | dispc_write_reg(DISPC_OVL_FIR_COEF_V2(plane, reg), value); |
534 | } | 546 | } |
535 | 547 | ||
536 | static void dispc_ovl_set_scale_coef(enum omap_plane plane, int hscaleup, | 548 | static void dispc_ovl_set_scale_coef(enum omap_plane plane, int fir_hinc, |
537 | int vscaleup, int five_taps, | 549 | int fir_vinc, int five_taps, |
538 | enum omap_color_component color_comp) | 550 | enum omap_color_component color_comp) |
539 | { | 551 | { |
540 | /* Coefficients for horizontal up-sampling */ | 552 | const struct dispc_coef *h_coef, *v_coef; |
541 | static const struct dispc_h_coef coef_hup[8] = { | ||
542 | { 0, 0, 128, 0, 0 }, | ||
543 | { -1, 13, 124, -8, 0 }, | ||
544 | { -2, 30, 112, -11, -1 }, | ||
545 | { -5, 51, 95, -11, -2 }, | ||
546 | { 0, -9, 73, 73, -9 }, | ||
547 | { -2, -11, 95, 51, -5 }, | ||
548 | { -1, -11, 112, 30, -2 }, | ||
549 | { 0, -8, 124, 13, -1 }, | ||
550 | }; | ||
551 | |||
552 | /* Coefficients for vertical up-sampling */ | ||
553 | static const struct dispc_v_coef coef_vup_3tap[8] = { | ||
554 | { 0, 0, 128, 0, 0 }, | ||
555 | { 0, 3, 123, 2, 0 }, | ||
556 | { 0, 12, 111, 5, 0 }, | ||
557 | { 0, 32, 89, 7, 0 }, | ||
558 | { 0, 0, 64, 64, 0 }, | ||
559 | { 0, 7, 89, 32, 0 }, | ||
560 | { 0, 5, 111, 12, 0 }, | ||
561 | { 0, 2, 123, 3, 0 }, | ||
562 | }; | ||
563 | |||
564 | static const struct dispc_v_coef coef_vup_5tap[8] = { | ||
565 | { 0, 0, 128, 0, 0 }, | ||
566 | { -1, 13, 124, -8, 0 }, | ||
567 | { -2, 30, 112, -11, -1 }, | ||
568 | { -5, 51, 95, -11, -2 }, | ||
569 | { 0, -9, 73, 73, -9 }, | ||
570 | { -2, -11, 95, 51, -5 }, | ||
571 | { -1, -11, 112, 30, -2 }, | ||
572 | { 0, -8, 124, 13, -1 }, | ||
573 | }; | ||
574 | |||
575 | /* Coefficients for horizontal down-sampling */ | ||
576 | static const struct dispc_h_coef coef_hdown[8] = { | ||
577 | { 0, 36, 56, 36, 0 }, | ||
578 | { 4, 40, 55, 31, -2 }, | ||
579 | { 8, 44, 54, 27, -5 }, | ||
580 | { 12, 48, 53, 22, -7 }, | ||
581 | { -9, 17, 52, 51, 17 }, | ||
582 | { -7, 22, 53, 48, 12 }, | ||
583 | { -5, 27, 54, 44, 8 }, | ||
584 | { -2, 31, 55, 40, 4 }, | ||
585 | }; | ||
586 | |||
587 | /* Coefficients for vertical down-sampling */ | ||
588 | static const struct dispc_v_coef coef_vdown_3tap[8] = { | ||
589 | { 0, 36, 56, 36, 0 }, | ||
590 | { 0, 40, 57, 31, 0 }, | ||
591 | { 0, 45, 56, 27, 0 }, | ||
592 | { 0, 50, 55, 23, 0 }, | ||
593 | { 0, 18, 55, 55, 0 }, | ||
594 | { 0, 23, 55, 50, 0 }, | ||
595 | { 0, 27, 56, 45, 0 }, | ||
596 | { 0, 31, 57, 40, 0 }, | ||
597 | }; | ||
598 | |||
599 | static const struct dispc_v_coef coef_vdown_5tap[8] = { | ||
600 | { 0, 36, 56, 36, 0 }, | ||
601 | { 4, 40, 55, 31, -2 }, | ||
602 | { 8, 44, 54, 27, -5 }, | ||
603 | { 12, 48, 53, 22, -7 }, | ||
604 | { -9, 17, 52, 51, 17 }, | ||
605 | { -7, 22, 53, 48, 12 }, | ||
606 | { -5, 27, 54, 44, 8 }, | ||
607 | { -2, 31, 55, 40, 4 }, | ||
608 | }; | ||
609 | |||
610 | const struct dispc_h_coef *h_coef; | ||
611 | const struct dispc_v_coef *v_coef; | ||
612 | int i; | 553 | int i; |
613 | 554 | ||
614 | if (hscaleup) | 555 | h_coef = dispc_ovl_get_scale_coef(fir_hinc, true); |
615 | h_coef = coef_hup; | 556 | v_coef = dispc_ovl_get_scale_coef(fir_vinc, five_taps); |
616 | else | ||
617 | h_coef = coef_hdown; | ||
618 | |||
619 | if (vscaleup) | ||
620 | v_coef = five_taps ? coef_vup_5tap : coef_vup_3tap; | ||
621 | else | ||
622 | v_coef = five_taps ? coef_vdown_5tap : coef_vdown_3tap; | ||
623 | 557 | ||
624 | for (i = 0; i < 8; i++) { | 558 | for (i = 0; i < 8; i++) { |
625 | u32 h, hv; | 559 | u32 h, hv; |
626 | 560 | ||
627 | h = FLD_VAL(h_coef[i].hc0, 7, 0) | 561 | h = FLD_VAL(h_coef[i].hc0_vc00, 7, 0) |
628 | | FLD_VAL(h_coef[i].hc1, 15, 8) | 562 | | FLD_VAL(h_coef[i].hc1_vc0, 15, 8) |
629 | | FLD_VAL(h_coef[i].hc2, 23, 16) | 563 | | FLD_VAL(h_coef[i].hc2_vc1, 23, 16) |
630 | | FLD_VAL(h_coef[i].hc3, 31, 24); | 564 | | FLD_VAL(h_coef[i].hc3_vc2, 31, 24); |
631 | hv = FLD_VAL(h_coef[i].hc4, 7, 0) | 565 | hv = FLD_VAL(h_coef[i].hc4_vc22, 7, 0) |
632 | | FLD_VAL(v_coef[i].vc0, 15, 8) | 566 | | FLD_VAL(v_coef[i].hc1_vc0, 15, 8) |
633 | | FLD_VAL(v_coef[i].vc1, 23, 16) | 567 | | FLD_VAL(v_coef[i].hc2_vc1, 23, 16) |
634 | | FLD_VAL(v_coef[i].vc2, 31, 24); | 568 | | FLD_VAL(v_coef[i].hc3_vc2, 31, 24); |
635 | 569 | ||
636 | if (color_comp == DISPC_COLOR_COMPONENT_RGB_Y) { | 570 | if (color_comp == DISPC_COLOR_COMPONENT_RGB_Y) { |
637 | dispc_ovl_write_firh_reg(plane, i, h); | 571 | dispc_ovl_write_firh_reg(plane, i, h); |
@@ -646,8 +580,8 @@ static void dispc_ovl_set_scale_coef(enum omap_plane plane, int hscaleup, | |||
646 | if (five_taps) { | 580 | if (five_taps) { |
647 | for (i = 0; i < 8; i++) { | 581 | for (i = 0; i < 8; i++) { |
648 | u32 v; | 582 | u32 v; |
649 | v = FLD_VAL(v_coef[i].vc00, 7, 0) | 583 | v = FLD_VAL(v_coef[i].hc0_vc00, 7, 0) |
650 | | FLD_VAL(v_coef[i].vc22, 15, 8); | 584 | | FLD_VAL(v_coef[i].hc4_vc22, 15, 8); |
651 | if (color_comp == DISPC_COLOR_COMPONENT_RGB_Y) | 585 | if (color_comp == DISPC_COLOR_COMPONENT_RGB_Y) |
652 | dispc_ovl_write_firv_reg(plane, i, v); | 586 | dispc_ovl_write_firv_reg(plane, i, v); |
653 | else | 587 | else |
@@ -875,8 +809,7 @@ static void dispc_ovl_set_color_mode(enum omap_plane plane, | |||
875 | REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane), m, 4, 1); | 809 | REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane), m, 4, 1); |
876 | } | 810 | } |
877 | 811 | ||
878 | static void dispc_ovl_set_channel_out(enum omap_plane plane, | 812 | void dispc_ovl_set_channel_out(enum omap_plane plane, enum omap_channel channel) |
879 | enum omap_channel channel) | ||
880 | { | 813 | { |
881 | int shift; | 814 | int shift; |
882 | u32 val; | 815 | u32 val; |
@@ -923,6 +856,39 @@ static void dispc_ovl_set_channel_out(enum omap_plane plane, | |||
923 | dispc_write_reg(DISPC_OVL_ATTRIBUTES(plane), val); | 856 | dispc_write_reg(DISPC_OVL_ATTRIBUTES(plane), val); |
924 | } | 857 | } |
925 | 858 | ||
859 | static enum omap_channel dispc_ovl_get_channel_out(enum omap_plane plane) | ||
860 | { | ||
861 | int shift; | ||
862 | u32 val; | ||
863 | enum omap_channel channel; | ||
864 | |||
865 | switch (plane) { | ||
866 | case OMAP_DSS_GFX: | ||
867 | shift = 8; | ||
868 | break; | ||
869 | case OMAP_DSS_VIDEO1: | ||
870 | case OMAP_DSS_VIDEO2: | ||
871 | case OMAP_DSS_VIDEO3: | ||
872 | shift = 16; | ||
873 | break; | ||
874 | default: | ||
875 | BUG(); | ||
876 | } | ||
877 | |||
878 | val = dispc_read_reg(DISPC_OVL_ATTRIBUTES(plane)); | ||
879 | |||
880 | if (dss_has_feature(FEAT_MGR_LCD2)) { | ||
881 | if (FLD_GET(val, 31, 30) == 0) | ||
882 | channel = FLD_GET(val, shift, shift); | ||
883 | else | ||
884 | channel = OMAP_DSS_CHANNEL_LCD2; | ||
885 | } else { | ||
886 | channel = FLD_GET(val, shift, shift); | ||
887 | } | ||
888 | |||
889 | return channel; | ||
890 | } | ||
891 | |||
926 | static void dispc_ovl_set_burst_size(enum omap_plane plane, | 892 | static void dispc_ovl_set_burst_size(enum omap_plane plane, |
927 | enum omap_burst_size burst_size) | 893 | enum omap_burst_size burst_size) |
928 | { | 894 | { |
@@ -964,7 +930,7 @@ void dispc_enable_gamma_table(bool enable) | |||
964 | REG_FLD_MOD(DISPC_CONFIG, enable, 9, 9); | 930 | REG_FLD_MOD(DISPC_CONFIG, enable, 9, 9); |
965 | } | 931 | } |
966 | 932 | ||
967 | void dispc_mgr_enable_cpr(enum omap_channel channel, bool enable) | 933 | static void dispc_mgr_enable_cpr(enum omap_channel channel, bool enable) |
968 | { | 934 | { |
969 | u16 reg; | 935 | u16 reg; |
970 | 936 | ||
@@ -978,7 +944,7 @@ void dispc_mgr_enable_cpr(enum omap_channel channel, bool enable) | |||
978 | REG_FLD_MOD(reg, enable, 15, 15); | 944 | REG_FLD_MOD(reg, enable, 15, 15); |
979 | } | 945 | } |
980 | 946 | ||
981 | void dispc_mgr_set_cpr_coef(enum omap_channel channel, | 947 | static void dispc_mgr_set_cpr_coef(enum omap_channel channel, |
982 | struct omap_dss_cpr_coefs *coefs) | 948 | struct omap_dss_cpr_coefs *coefs) |
983 | { | 949 | { |
984 | u32 coef_r, coef_g, coef_b; | 950 | u32 coef_r, coef_g, coef_b; |
@@ -1057,8 +1023,7 @@ u32 dispc_ovl_get_fifo_size(enum omap_plane plane) | |||
1057 | return dispc.fifo_size[plane]; | 1023 | return dispc.fifo_size[plane]; |
1058 | } | 1024 | } |
1059 | 1025 | ||
1060 | static void dispc_ovl_set_fifo_threshold(enum omap_plane plane, u32 low, | 1026 | void dispc_ovl_set_fifo_threshold(enum omap_plane plane, u32 low, u32 high) |
1061 | u32 high) | ||
1062 | { | 1027 | { |
1063 | u8 hi_start, hi_end, lo_start, lo_end; | 1028 | u8 hi_start, hi_end, lo_start, lo_end; |
1064 | u32 unit; | 1029 | u32 unit; |
@@ -1169,17 +1134,12 @@ static void dispc_ovl_set_scale_param(enum omap_plane plane, | |||
1169 | enum omap_color_component color_comp) | 1134 | enum omap_color_component color_comp) |
1170 | { | 1135 | { |
1171 | int fir_hinc, fir_vinc; | 1136 | int fir_hinc, fir_vinc; |
1172 | int hscaleup, vscaleup; | ||
1173 | |||
1174 | hscaleup = orig_width <= out_width; | ||
1175 | vscaleup = orig_height <= out_height; | ||
1176 | |||
1177 | dispc_ovl_set_scale_coef(plane, hscaleup, vscaleup, five_taps, | ||
1178 | color_comp); | ||
1179 | 1137 | ||
1180 | fir_hinc = 1024 * orig_width / out_width; | 1138 | fir_hinc = 1024 * orig_width / out_width; |
1181 | fir_vinc = 1024 * orig_height / out_height; | 1139 | fir_vinc = 1024 * orig_height / out_height; |
1182 | 1140 | ||
1141 | dispc_ovl_set_scale_coef(plane, fir_hinc, fir_vinc, five_taps, | ||
1142 | color_comp); | ||
1183 | dispc_ovl_set_fir(plane, fir_hinc, fir_vinc, color_comp); | 1143 | dispc_ovl_set_fir(plane, fir_hinc, fir_vinc, color_comp); |
1184 | } | 1144 | } |
1185 | 1145 | ||
@@ -1654,6 +1614,9 @@ static unsigned long calc_fclk_five_taps(enum omap_channel channel, u16 width, | |||
1654 | u32 fclk = 0; | 1614 | u32 fclk = 0; |
1655 | u64 tmp, pclk = dispc_mgr_pclk_rate(channel); | 1615 | u64 tmp, pclk = dispc_mgr_pclk_rate(channel); |
1656 | 1616 | ||
1617 | if (height <= out_height && width <= out_width) | ||
1618 | return (unsigned long) pclk; | ||
1619 | |||
1657 | if (height > out_height) { | 1620 | if (height > out_height) { |
1658 | struct omap_dss_device *dssdev = dispc_mgr_get_device(channel); | 1621 | struct omap_dss_device *dssdev = dispc_mgr_get_device(channel); |
1659 | unsigned int ppl = dssdev->panel.timings.x_res; | 1622 | unsigned int ppl = dssdev->panel.timings.x_res; |
@@ -1708,7 +1671,16 @@ static unsigned long calc_fclk(enum omap_channel channel, u16 width, | |||
1708 | else | 1671 | else |
1709 | vf = 1; | 1672 | vf = 1; |
1710 | 1673 | ||
1711 | return dispc_mgr_pclk_rate(channel) * vf * hf; | 1674 | if (cpu_is_omap24xx()) { |
1675 | if (vf > 1 && hf > 1) | ||
1676 | return dispc_mgr_pclk_rate(channel) * 4; | ||
1677 | else | ||
1678 | return dispc_mgr_pclk_rate(channel) * 2; | ||
1679 | } else if (cpu_is_omap34xx()) { | ||
1680 | return dispc_mgr_pclk_rate(channel) * vf * hf; | ||
1681 | } else { | ||
1682 | return dispc_mgr_pclk_rate(channel) * hf; | ||
1683 | } | ||
1712 | } | 1684 | } |
1713 | 1685 | ||
1714 | static int dispc_ovl_calc_scaling(enum omap_plane plane, | 1686 | static int dispc_ovl_calc_scaling(enum omap_plane plane, |
@@ -1718,6 +1690,8 @@ static int dispc_ovl_calc_scaling(enum omap_plane plane, | |||
1718 | { | 1690 | { |
1719 | struct omap_overlay *ovl = omap_dss_get_overlay(plane); | 1691 | struct omap_overlay *ovl = omap_dss_get_overlay(plane); |
1720 | const int maxdownscale = dss_feat_get_param_max(FEAT_PARAM_DOWNSCALE); | 1692 | const int maxdownscale = dss_feat_get_param_max(FEAT_PARAM_DOWNSCALE); |
1693 | const int maxsinglelinewidth = | ||
1694 | dss_feat_get_param_max(FEAT_PARAM_LINEWIDTH); | ||
1721 | unsigned long fclk = 0; | 1695 | unsigned long fclk = 0; |
1722 | 1696 | ||
1723 | if (width == out_width && height == out_height) | 1697 | if (width == out_width && height == out_height) |
@@ -1734,28 +1708,40 @@ static int dispc_ovl_calc_scaling(enum omap_plane plane, | |||
1734 | out_height > height * 8) | 1708 | out_height > height * 8) |
1735 | return -EINVAL; | 1709 | return -EINVAL; |
1736 | 1710 | ||
1737 | /* Must use 5-tap filter? */ | 1711 | if (cpu_is_omap24xx()) { |
1738 | *five_taps = height > out_height * 2; | 1712 | if (width > maxsinglelinewidth) |
1739 | 1713 | DSSERR("Cannot scale max input width exceeded"); | |
1740 | if (!*five_taps) { | 1714 | *five_taps = false; |
1715 | fclk = calc_fclk(channel, width, height, out_width, | ||
1716 | out_height); | ||
1717 | } else if (cpu_is_omap34xx()) { | ||
1718 | if (width > (maxsinglelinewidth * 2)) { | ||
1719 | DSSERR("Cannot setup scaling"); | ||
1720 | DSSERR("width exceeds maximum width possible"); | ||
1721 | return -EINVAL; | ||
1722 | } | ||
1723 | fclk = calc_fclk_five_taps(channel, width, height, out_width, | ||
1724 | out_height, color_mode); | ||
1725 | if (width > maxsinglelinewidth) { | ||
1726 | if (height > out_height && height < out_height * 2) | ||
1727 | *five_taps = false; | ||
1728 | else { | ||
1729 | DSSERR("cannot setup scaling with five taps"); | ||
1730 | return -EINVAL; | ||
1731 | } | ||
1732 | } | ||
1733 | if (!*five_taps) | ||
1734 | fclk = calc_fclk(channel, width, height, out_width, | ||
1735 | out_height); | ||
1736 | } else { | ||
1737 | if (width > maxsinglelinewidth) { | ||
1738 | DSSERR("Cannot scale width exceeds max line width"); | ||
1739 | return -EINVAL; | ||
1740 | } | ||
1741 | fclk = calc_fclk(channel, width, height, out_width, | 1741 | fclk = calc_fclk(channel, width, height, out_width, |
1742 | out_height); | 1742 | out_height); |
1743 | |||
1744 | /* Try 5-tap filter if 3-tap fclk is too high */ | ||
1745 | if (cpu_is_omap34xx() && height > out_height && | ||
1746 | fclk > dispc_fclk_rate()) | ||
1747 | *five_taps = true; | ||
1748 | } | ||
1749 | |||
1750 | if (width > (2048 >> *five_taps)) { | ||
1751 | DSSERR("failed to set up scaling, fclk too low\n"); | ||
1752 | return -EINVAL; | ||
1753 | } | 1743 | } |
1754 | 1744 | ||
1755 | if (*five_taps) | ||
1756 | fclk = calc_fclk_five_taps(channel, width, height, | ||
1757 | out_width, out_height, color_mode); | ||
1758 | |||
1759 | DSSDBG("required fclk rate = %lu Hz\n", fclk); | 1745 | DSSDBG("required fclk rate = %lu Hz\n", fclk); |
1760 | DSSDBG("current fclk rate = %lu Hz\n", dispc_fclk_rate()); | 1746 | DSSDBG("current fclk rate = %lu Hz\n", dispc_fclk_rate()); |
1761 | 1747 | ||
@@ -1771,11 +1757,10 @@ static int dispc_ovl_calc_scaling(enum omap_plane plane, | |||
1771 | } | 1757 | } |
1772 | 1758 | ||
1773 | int dispc_ovl_setup(enum omap_plane plane, struct omap_overlay_info *oi, | 1759 | int dispc_ovl_setup(enum omap_plane plane, struct omap_overlay_info *oi, |
1774 | bool ilace, enum omap_channel channel, bool replication, | 1760 | bool ilace, bool replication) |
1775 | u32 fifo_low, u32 fifo_high) | ||
1776 | { | 1761 | { |
1777 | struct omap_overlay *ovl = omap_dss_get_overlay(plane); | 1762 | struct omap_overlay *ovl = omap_dss_get_overlay(plane); |
1778 | bool five_taps = false; | 1763 | bool five_taps = true; |
1779 | bool fieldmode = 0; | 1764 | bool fieldmode = 0; |
1780 | int r, cconv = 0; | 1765 | int r, cconv = 0; |
1781 | unsigned offset0, offset1; | 1766 | unsigned offset0, offset1; |
@@ -1783,36 +1768,43 @@ int dispc_ovl_setup(enum omap_plane plane, struct omap_overlay_info *oi, | |||
1783 | s32 pix_inc; | 1768 | s32 pix_inc; |
1784 | u16 frame_height = oi->height; | 1769 | u16 frame_height = oi->height; |
1785 | unsigned int field_offset = 0; | 1770 | unsigned int field_offset = 0; |
1771 | u16 outw, outh; | ||
1772 | enum omap_channel channel; | ||
1773 | |||
1774 | channel = dispc_ovl_get_channel_out(plane); | ||
1786 | 1775 | ||
1787 | DSSDBG("dispc_ovl_setup %d, pa %x, pa_uv %x, sw %d, %d,%d, %dx%d -> " | 1776 | DSSDBG("dispc_ovl_setup %d, pa %x, pa_uv %x, sw %d, %d,%d, %dx%d -> " |
1788 | "%dx%d, cmode %x, rot %d, mir %d, ilace %d chan %d repl %d " | 1777 | "%dx%d, cmode %x, rot %d, mir %d, ilace %d chan %d repl %d\n", |
1789 | "fifo_low %d fifo high %d\n", plane, oi->paddr, oi->p_uv_addr, | 1778 | plane, oi->paddr, oi->p_uv_addr, |
1790 | oi->screen_width, oi->pos_x, oi->pos_y, oi->width, oi->height, | 1779 | oi->screen_width, oi->pos_x, oi->pos_y, oi->width, oi->height, |
1791 | oi->out_width, oi->out_height, oi->color_mode, oi->rotation, | 1780 | oi->out_width, oi->out_height, oi->color_mode, oi->rotation, |
1792 | oi->mirror, ilace, channel, replication, fifo_low, fifo_high); | 1781 | oi->mirror, ilace, channel, replication); |
1793 | 1782 | ||
1794 | if (oi->paddr == 0) | 1783 | if (oi->paddr == 0) |
1795 | return -EINVAL; | 1784 | return -EINVAL; |
1796 | 1785 | ||
1797 | if (ilace && oi->height == oi->out_height) | 1786 | outw = oi->out_width == 0 ? oi->width : oi->out_width; |
1787 | outh = oi->out_height == 0 ? oi->height : oi->out_height; | ||
1788 | |||
1789 | if (ilace && oi->height == outh) | ||
1798 | fieldmode = 1; | 1790 | fieldmode = 1; |
1799 | 1791 | ||
1800 | if (ilace) { | 1792 | if (ilace) { |
1801 | if (fieldmode) | 1793 | if (fieldmode) |
1802 | oi->height /= 2; | 1794 | oi->height /= 2; |
1803 | oi->pos_y /= 2; | 1795 | oi->pos_y /= 2; |
1804 | oi->out_height /= 2; | 1796 | outh /= 2; |
1805 | 1797 | ||
1806 | DSSDBG("adjusting for ilace: height %d, pos_y %d, " | 1798 | DSSDBG("adjusting for ilace: height %d, pos_y %d, " |
1807 | "out_height %d\n", | 1799 | "out_height %d\n", |
1808 | oi->height, oi->pos_y, oi->out_height); | 1800 | oi->height, oi->pos_y, outh); |
1809 | } | 1801 | } |
1810 | 1802 | ||
1811 | if (!dss_feat_color_mode_supported(plane, oi->color_mode)) | 1803 | if (!dss_feat_color_mode_supported(plane, oi->color_mode)) |
1812 | return -EINVAL; | 1804 | return -EINVAL; |
1813 | 1805 | ||
1814 | r = dispc_ovl_calc_scaling(plane, channel, oi->width, oi->height, | 1806 | r = dispc_ovl_calc_scaling(plane, channel, oi->width, oi->height, |
1815 | oi->out_width, oi->out_height, oi->color_mode, | 1807 | outw, outh, oi->color_mode, |
1816 | &five_taps); | 1808 | &five_taps); |
1817 | if (r) | 1809 | if (r) |
1818 | return r; | 1810 | return r; |
@@ -1830,10 +1822,10 @@ int dispc_ovl_setup(enum omap_plane plane, struct omap_overlay_info *oi, | |||
1830 | * so the integer part must be added to the base address of the | 1822 | * so the integer part must be added to the base address of the |
1831 | * bottom field. | 1823 | * bottom field. |
1832 | */ | 1824 | */ |
1833 | if (!oi->height || oi->height == oi->out_height) | 1825 | if (!oi->height || oi->height == outh) |
1834 | field_offset = 0; | 1826 | field_offset = 0; |
1835 | else | 1827 | else |
1836 | field_offset = oi->height / oi->out_height / 2; | 1828 | field_offset = oi->height / outh / 2; |
1837 | } | 1829 | } |
1838 | 1830 | ||
1839 | /* Fields are independent but interleaved in memory. */ | 1831 | /* Fields are independent but interleaved in memory. */ |
@@ -1869,7 +1861,7 @@ int dispc_ovl_setup(enum omap_plane plane, struct omap_overlay_info *oi, | |||
1869 | dispc_ovl_set_pix_inc(plane, pix_inc); | 1861 | dispc_ovl_set_pix_inc(plane, pix_inc); |
1870 | 1862 | ||
1871 | DSSDBG("%d,%d %dx%d -> %dx%d\n", oi->pos_x, oi->pos_y, oi->width, | 1863 | DSSDBG("%d,%d %dx%d -> %dx%d\n", oi->pos_x, oi->pos_y, oi->width, |
1872 | oi->height, oi->out_width, oi->out_height); | 1864 | oi->height, outw, outh); |
1873 | 1865 | ||
1874 | dispc_ovl_set_pos(plane, oi->pos_x, oi->pos_y); | 1866 | dispc_ovl_set_pos(plane, oi->pos_x, oi->pos_y); |
1875 | 1867 | ||
@@ -1877,10 +1869,10 @@ int dispc_ovl_setup(enum omap_plane plane, struct omap_overlay_info *oi, | |||
1877 | 1869 | ||
1878 | if (ovl->caps & OMAP_DSS_OVL_CAP_SCALE) { | 1870 | if (ovl->caps & OMAP_DSS_OVL_CAP_SCALE) { |
1879 | dispc_ovl_set_scaling(plane, oi->width, oi->height, | 1871 | dispc_ovl_set_scaling(plane, oi->width, oi->height, |
1880 | oi->out_width, oi->out_height, | 1872 | outw, outh, |
1881 | ilace, five_taps, fieldmode, | 1873 | ilace, five_taps, fieldmode, |
1882 | oi->color_mode, oi->rotation); | 1874 | oi->color_mode, oi->rotation); |
1883 | dispc_ovl_set_vid_size(plane, oi->out_width, oi->out_height); | 1875 | dispc_ovl_set_vid_size(plane, outw, outh); |
1884 | dispc_ovl_set_vid_color_conv(plane, cconv); | 1876 | dispc_ovl_set_vid_color_conv(plane, cconv); |
1885 | } | 1877 | } |
1886 | 1878 | ||
@@ -1891,10 +1883,7 @@ int dispc_ovl_setup(enum omap_plane plane, struct omap_overlay_info *oi, | |||
1891 | dispc_ovl_set_pre_mult_alpha(plane, oi->pre_mult_alpha); | 1883 | dispc_ovl_set_pre_mult_alpha(plane, oi->pre_mult_alpha); |
1892 | dispc_ovl_setup_global_alpha(plane, oi->global_alpha); | 1884 | dispc_ovl_setup_global_alpha(plane, oi->global_alpha); |
1893 | 1885 | ||
1894 | dispc_ovl_set_channel_out(plane, channel); | ||
1895 | |||
1896 | dispc_ovl_enable_replication(plane, replication); | 1886 | dispc_ovl_enable_replication(plane, replication); |
1897 | dispc_ovl_set_fifo_threshold(plane, fifo_low, fifo_high); | ||
1898 | 1887 | ||
1899 | return 0; | 1888 | return 0; |
1900 | } | 1889 | } |
@@ -1916,10 +1905,14 @@ static void dispc_disable_isr(void *data, u32 mask) | |||
1916 | 1905 | ||
1917 | static void _enable_lcd_out(enum omap_channel channel, bool enable) | 1906 | static void _enable_lcd_out(enum omap_channel channel, bool enable) |
1918 | { | 1907 | { |
1919 | if (channel == OMAP_DSS_CHANNEL_LCD2) | 1908 | if (channel == OMAP_DSS_CHANNEL_LCD2) { |
1920 | REG_FLD_MOD(DISPC_CONTROL2, enable ? 1 : 0, 0, 0); | 1909 | REG_FLD_MOD(DISPC_CONTROL2, enable ? 1 : 0, 0, 0); |
1921 | else | 1910 | /* flush posted write */ |
1911 | dispc_read_reg(DISPC_CONTROL2); | ||
1912 | } else { | ||
1922 | REG_FLD_MOD(DISPC_CONTROL, enable ? 1 : 0, 0, 0); | 1913 | REG_FLD_MOD(DISPC_CONTROL, enable ? 1 : 0, 0, 0); |
1914 | dispc_read_reg(DISPC_CONTROL); | ||
1915 | } | ||
1923 | } | 1916 | } |
1924 | 1917 | ||
1925 | static void dispc_mgr_enable_lcd_out(enum omap_channel channel, bool enable) | 1918 | static void dispc_mgr_enable_lcd_out(enum omap_channel channel, bool enable) |
@@ -1967,6 +1960,8 @@ static void dispc_mgr_enable_lcd_out(enum omap_channel channel, bool enable) | |||
1967 | static void _enable_digit_out(bool enable) | 1960 | static void _enable_digit_out(bool enable) |
1968 | { | 1961 | { |
1969 | REG_FLD_MOD(DISPC_CONTROL, enable ? 1 : 0, 1, 1); | 1962 | REG_FLD_MOD(DISPC_CONTROL, enable ? 1 : 0, 1, 1); |
1963 | /* flush posted write */ | ||
1964 | dispc_read_reg(DISPC_CONTROL); | ||
1970 | } | 1965 | } |
1971 | 1966 | ||
1972 | static void dispc_mgr_enable_digit_out(bool enable) | 1967 | static void dispc_mgr_enable_digit_out(bool enable) |
@@ -2124,25 +2119,12 @@ void dispc_set_loadmode(enum omap_dss_load_mode mode) | |||
2124 | } | 2119 | } |
2125 | 2120 | ||
2126 | 2121 | ||
2127 | void dispc_mgr_set_default_color(enum omap_channel channel, u32 color) | 2122 | static void dispc_mgr_set_default_color(enum omap_channel channel, u32 color) |
2128 | { | 2123 | { |
2129 | dispc_write_reg(DISPC_DEFAULT_COLOR(channel), color); | 2124 | dispc_write_reg(DISPC_DEFAULT_COLOR(channel), color); |
2130 | } | 2125 | } |
2131 | 2126 | ||
2132 | u32 dispc_mgr_get_default_color(enum omap_channel channel) | 2127 | static void dispc_mgr_set_trans_key(enum omap_channel ch, |
2133 | { | ||
2134 | u32 l; | ||
2135 | |||
2136 | BUG_ON(channel != OMAP_DSS_CHANNEL_DIGIT && | ||
2137 | channel != OMAP_DSS_CHANNEL_LCD && | ||
2138 | channel != OMAP_DSS_CHANNEL_LCD2); | ||
2139 | |||
2140 | l = dispc_read_reg(DISPC_DEFAULT_COLOR(channel)); | ||
2141 | |||
2142 | return l; | ||
2143 | } | ||
2144 | |||
2145 | void dispc_mgr_set_trans_key(enum omap_channel ch, | ||
2146 | enum omap_dss_trans_key_type type, | 2128 | enum omap_dss_trans_key_type type, |
2147 | u32 trans_key) | 2129 | u32 trans_key) |
2148 | { | 2130 | { |
@@ -2156,26 +2138,7 @@ void dispc_mgr_set_trans_key(enum omap_channel ch, | |||
2156 | dispc_write_reg(DISPC_TRANS_COLOR(ch), trans_key); | 2138 | dispc_write_reg(DISPC_TRANS_COLOR(ch), trans_key); |
2157 | } | 2139 | } |
2158 | 2140 | ||
2159 | void dispc_mgr_get_trans_key(enum omap_channel ch, | 2141 | static void dispc_mgr_enable_trans_key(enum omap_channel ch, bool enable) |
2160 | enum omap_dss_trans_key_type *type, | ||
2161 | u32 *trans_key) | ||
2162 | { | ||
2163 | if (type) { | ||
2164 | if (ch == OMAP_DSS_CHANNEL_LCD) | ||
2165 | *type = REG_GET(DISPC_CONFIG, 11, 11); | ||
2166 | else if (ch == OMAP_DSS_CHANNEL_DIGIT) | ||
2167 | *type = REG_GET(DISPC_CONFIG, 13, 13); | ||
2168 | else if (ch == OMAP_DSS_CHANNEL_LCD2) | ||
2169 | *type = REG_GET(DISPC_CONFIG2, 11, 11); | ||
2170 | else | ||
2171 | BUG(); | ||
2172 | } | ||
2173 | |||
2174 | if (trans_key) | ||
2175 | *trans_key = dispc_read_reg(DISPC_TRANS_COLOR(ch)); | ||
2176 | } | ||
2177 | |||
2178 | void dispc_mgr_enable_trans_key(enum omap_channel ch, bool enable) | ||
2179 | { | 2142 | { |
2180 | if (ch == OMAP_DSS_CHANNEL_LCD) | 2143 | if (ch == OMAP_DSS_CHANNEL_LCD) |
2181 | REG_FLD_MOD(DISPC_CONFIG, enable, 10, 10); | 2144 | REG_FLD_MOD(DISPC_CONFIG, enable, 10, 10); |
@@ -2185,7 +2148,8 @@ void dispc_mgr_enable_trans_key(enum omap_channel ch, bool enable) | |||
2185 | REG_FLD_MOD(DISPC_CONFIG2, enable, 10, 10); | 2148 | REG_FLD_MOD(DISPC_CONFIG2, enable, 10, 10); |
2186 | } | 2149 | } |
2187 | 2150 | ||
2188 | void dispc_mgr_enable_alpha_fixed_zorder(enum omap_channel ch, bool enable) | 2151 | static void dispc_mgr_enable_alpha_fixed_zorder(enum omap_channel ch, |
2152 | bool enable) | ||
2189 | { | 2153 | { |
2190 | if (!dss_has_feature(FEAT_ALPHA_FIXED_ZORDER)) | 2154 | if (!dss_has_feature(FEAT_ALPHA_FIXED_ZORDER)) |
2191 | return; | 2155 | return; |
@@ -2196,40 +2160,20 @@ void dispc_mgr_enable_alpha_fixed_zorder(enum omap_channel ch, bool enable) | |||
2196 | REG_FLD_MOD(DISPC_CONFIG, enable, 19, 19); | 2160 | REG_FLD_MOD(DISPC_CONFIG, enable, 19, 19); |
2197 | } | 2161 | } |
2198 | 2162 | ||
2199 | bool dispc_mgr_alpha_fixed_zorder_enabled(enum omap_channel ch) | 2163 | void dispc_mgr_setup(enum omap_channel channel, |
2200 | { | 2164 | struct omap_overlay_manager_info *info) |
2201 | bool enabled; | ||
2202 | |||
2203 | if (!dss_has_feature(FEAT_ALPHA_FIXED_ZORDER)) | ||
2204 | return false; | ||
2205 | |||
2206 | if (ch == OMAP_DSS_CHANNEL_LCD) | ||
2207 | enabled = REG_GET(DISPC_CONFIG, 18, 18); | ||
2208 | else if (ch == OMAP_DSS_CHANNEL_DIGIT) | ||
2209 | enabled = REG_GET(DISPC_CONFIG, 19, 19); | ||
2210 | else | ||
2211 | BUG(); | ||
2212 | |||
2213 | return enabled; | ||
2214 | } | ||
2215 | |||
2216 | bool dispc_mgr_trans_key_enabled(enum omap_channel ch) | ||
2217 | { | 2165 | { |
2218 | bool enabled; | 2166 | dispc_mgr_set_default_color(channel, info->default_color); |
2219 | 2167 | dispc_mgr_set_trans_key(channel, info->trans_key_type, info->trans_key); | |
2220 | if (ch == OMAP_DSS_CHANNEL_LCD) | 2168 | dispc_mgr_enable_trans_key(channel, info->trans_enabled); |
2221 | enabled = REG_GET(DISPC_CONFIG, 10, 10); | 2169 | dispc_mgr_enable_alpha_fixed_zorder(channel, |
2222 | else if (ch == OMAP_DSS_CHANNEL_DIGIT) | 2170 | info->partial_alpha_enabled); |
2223 | enabled = REG_GET(DISPC_CONFIG, 12, 12); | 2171 | if (dss_has_feature(FEAT_CPR)) { |
2224 | else if (ch == OMAP_DSS_CHANNEL_LCD2) | 2172 | dispc_mgr_enable_cpr(channel, info->cpr_enable); |
2225 | enabled = REG_GET(DISPC_CONFIG2, 10, 10); | 2173 | dispc_mgr_set_cpr_coef(channel, &info->cpr_coefs); |
2226 | else | 2174 | } |
2227 | BUG(); | ||
2228 | |||
2229 | return enabled; | ||
2230 | } | 2175 | } |
2231 | 2176 | ||
2232 | |||
2233 | void dispc_mgr_set_tft_data_lines(enum omap_channel channel, u8 data_lines) | 2177 | void dispc_mgr_set_tft_data_lines(enum omap_channel channel, u8 data_lines) |
2234 | { | 2178 | { |
2235 | int code; | 2179 | int code; |
@@ -3184,7 +3128,8 @@ static void dispc_error_worker(struct work_struct *work) | |||
3184 | for (i = 0; i < omap_dss_get_num_overlay_managers(); ++i) { | 3128 | for (i = 0; i < omap_dss_get_num_overlay_managers(); ++i) { |
3185 | struct omap_overlay_manager *mgr; | 3129 | struct omap_overlay_manager *mgr; |
3186 | mgr = omap_dss_get_overlay_manager(i); | 3130 | mgr = omap_dss_get_overlay_manager(i); |
3187 | mgr->device->driver->disable(mgr->device); | 3131 | if (mgr->device && mgr->device->driver) |
3132 | mgr->device->driver->disable(mgr->device); | ||
3188 | } | 3133 | } |
3189 | } | 3134 | } |
3190 | 3135 | ||
diff --git a/drivers/video/omap2/dss/dispc.h b/drivers/video/omap2/dss/dispc.h index c06efc38983e..5836bd1650f9 100644 --- a/drivers/video/omap2/dss/dispc.h +++ b/drivers/video/omap2/dss/dispc.h | |||
@@ -97,6 +97,17 @@ | |||
97 | #define DISPC_OVL_PRELOAD(n) (DISPC_OVL_BASE(n) + \ | 97 | #define DISPC_OVL_PRELOAD(n) (DISPC_OVL_BASE(n) + \ |
98 | DISPC_PRELOAD_OFFSET(n)) | 98 | DISPC_PRELOAD_OFFSET(n)) |
99 | 99 | ||
100 | /* DISPC up/downsampling FIR filter coefficient structure */ | ||
101 | struct dispc_coef { | ||
102 | s8 hc4_vc22; | ||
103 | s8 hc3_vc2; | ||
104 | u8 hc2_vc1; | ||
105 | s8 hc1_vc0; | ||
106 | s8 hc0_vc00; | ||
107 | }; | ||
108 | |||
109 | const struct dispc_coef *dispc_ovl_get_scale_coef(int inc, int five_taps); | ||
110 | |||
100 | /* DISPC manager/channel specific registers */ | 111 | /* DISPC manager/channel specific registers */ |
101 | static inline u16 DISPC_DEFAULT_COLOR(enum omap_channel channel) | 112 | static inline u16 DISPC_DEFAULT_COLOR(enum omap_channel channel) |
102 | { | 113 | { |
diff --git a/drivers/video/omap2/dss/dispc_coefs.c b/drivers/video/omap2/dss/dispc_coefs.c new file mode 100644 index 000000000000..069bccbb3f12 --- /dev/null +++ b/drivers/video/omap2/dss/dispc_coefs.c | |||
@@ -0,0 +1,326 @@ | |||
1 | /* | ||
2 | * linux/drivers/video/omap2/dss/dispc_coefs.c | ||
3 | * | ||
4 | * Copyright (C) 2011 Texas Instruments | ||
5 | * Author: Chandrabhanu Mahapatra <cmahapatra@ti.com> | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify it | ||
8 | * under the terms of the GNU General Public License version 2 as published by | ||
9 | * the Free Software Foundation. | ||
10 | * | ||
11 | * This program is distributed in the hope that it will be useful, but WITHOUT | ||
12 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
13 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
14 | * more details. | ||
15 | * | ||
16 | * You should have received a copy of the GNU General Public License along with | ||
17 | * this program. If not, see <http://www.gnu.org/licenses/>. | ||
18 | */ | ||
19 | |||
20 | #include <linux/kernel.h> | ||
21 | #include <video/omapdss.h> | ||
22 | #include "dispc.h" | ||
23 | |||
24 | #define ARRAY_LEN(array) (sizeof(array) / sizeof(array[0])) | ||
25 | |||
26 | static const struct dispc_coef coef3_M8[8] = { | ||
27 | { 0, 0, 128, 0, 0 }, | ||
28 | { 0, -4, 123, 9, 0 }, | ||
29 | { 0, -4, 108, 87, 0 }, | ||
30 | { 0, -2, 87, 43, 0 }, | ||
31 | { 0, 64, 64, 0, 0 }, | ||
32 | { 0, 43, 87, -2, 0 }, | ||
33 | { 0, 24, 108, -4, 0 }, | ||
34 | { 0, 9, 123, -4, 0 }, | ||
35 | }; | ||
36 | |||
37 | static const struct dispc_coef coef3_M9[8] = { | ||
38 | { 0, 6, 116, 6, 0 }, | ||
39 | { 0, 0, 112, 16, 0 }, | ||
40 | { 0, -2, 100, 30, 0 }, | ||
41 | { 0, -2, 83, 47, 0 }, | ||
42 | { 0, 64, 64, 0, 0 }, | ||
43 | { 0, 47, 83, -2, 0 }, | ||
44 | { 0, 30, 100, -2, 0 }, | ||
45 | { 0, 16, 112, 0, 0 }, | ||
46 | }; | ||
47 | |||
48 | static const struct dispc_coef coef3_M10[8] = { | ||
49 | { 0, 10, 108, 10, 0 }, | ||
50 | { 0, 3, 104, 21, 0 }, | ||
51 | { 0, 0, 94, 34, 0 }, | ||
52 | { 0, -1, 80, 49, 0 }, | ||
53 | { 0, 64, 64, 0, 0 }, | ||
54 | { 0, 49, 80, -1, 0 }, | ||
55 | { 0, 34, 94, 0, 0 }, | ||
56 | { 0, 21, 104, 3, 0 }, | ||
57 | }; | ||
58 | |||
59 | static const struct dispc_coef coef3_M11[8] = { | ||
60 | { 0, 14, 100, 14, 0 }, | ||
61 | { 0, 6, 98, 24, 0 }, | ||
62 | { 0, 2, 90, 36, 0 }, | ||
63 | { 0, 0, 78, 50, 0 }, | ||
64 | { 0, 64, 64, 0, 0 }, | ||
65 | { 0, 50, 78, 0, 0 }, | ||
66 | { 0, 36, 90, 2, 0 }, | ||
67 | { 0, 24, 98, 6, 0 }, | ||
68 | }; | ||
69 | |||
70 | static const struct dispc_coef coef3_M12[8] = { | ||
71 | { 0, 16, 96, 16, 0 }, | ||
72 | { 0, 9, 93, 26, 0 }, | ||
73 | { 0, 4, 86, 38, 0 }, | ||
74 | { 0, 1, 76, 51, 0 }, | ||
75 | { 0, 64, 64, 0, 0 }, | ||
76 | { 0, 51, 76, 1, 0 }, | ||
77 | { 0, 38, 86, 4, 0 }, | ||
78 | { 0, 26, 93, 9, 0 }, | ||
79 | }; | ||
80 | |||
81 | static const struct dispc_coef coef3_M13[8] = { | ||
82 | { 0, 18, 92, 18, 0 }, | ||
83 | { 0, 10, 90, 28, 0 }, | ||
84 | { 0, 5, 83, 40, 0 }, | ||
85 | { 0, 1, 75, 52, 0 }, | ||
86 | { 0, 64, 64, 0, 0 }, | ||
87 | { 0, 52, 75, 1, 0 }, | ||
88 | { 0, 40, 83, 5, 0 }, | ||
89 | { 0, 28, 90, 10, 0 }, | ||
90 | }; | ||
91 | |||
92 | static const struct dispc_coef coef3_M14[8] = { | ||
93 | { 0, 20, 88, 20, 0 }, | ||
94 | { 0, 12, 86, 30, 0 }, | ||
95 | { 0, 6, 81, 41, 0 }, | ||
96 | { 0, 2, 74, 52, 0 }, | ||
97 | { 0, 64, 64, 0, 0 }, | ||
98 | { 0, 52, 74, 2, 0 }, | ||
99 | { 0, 41, 81, 6, 0 }, | ||
100 | { 0, 30, 86, 12, 0 }, | ||
101 | }; | ||
102 | |||
103 | static const struct dispc_coef coef3_M16[8] = { | ||
104 | { 0, 22, 84, 22, 0 }, | ||
105 | { 0, 14, 82, 32, 0 }, | ||
106 | { 0, 8, 78, 42, 0 }, | ||
107 | { 0, 3, 72, 53, 0 }, | ||
108 | { 0, 64, 64, 0, 0 }, | ||
109 | { 0, 53, 72, 3, 0 }, | ||
110 | { 0, 42, 78, 8, 0 }, | ||
111 | { 0, 32, 82, 14, 0 }, | ||
112 | }; | ||
113 | |||
114 | static const struct dispc_coef coef3_M19[8] = { | ||
115 | { 0, 24, 80, 24, 0 }, | ||
116 | { 0, 16, 79, 33, 0 }, | ||
117 | { 0, 9, 76, 43, 0 }, | ||
118 | { 0, 4, 70, 54, 0 }, | ||
119 | { 0, 64, 64, 0, 0 }, | ||
120 | { 0, 54, 70, 4, 0 }, | ||
121 | { 0, 43, 76, 9, 0 }, | ||
122 | { 0, 33, 79, 16, 0 }, | ||
123 | }; | ||
124 | |||
125 | static const struct dispc_coef coef3_M22[8] = { | ||
126 | { 0, 25, 78, 25, 0 }, | ||
127 | { 0, 17, 77, 34, 0 }, | ||
128 | { 0, 10, 74, 44, 0 }, | ||
129 | { 0, 5, 69, 54, 0 }, | ||
130 | { 0, 64, 64, 0, 0 }, | ||
131 | { 0, 54, 69, 5, 0 }, | ||
132 | { 0, 44, 74, 10, 0 }, | ||
133 | { 0, 34, 77, 17, 0 }, | ||
134 | }; | ||
135 | |||
136 | static const struct dispc_coef coef3_M26[8] = { | ||
137 | { 0, 26, 76, 26, 0 }, | ||
138 | { 0, 19, 74, 35, 0 }, | ||
139 | { 0, 11, 72, 45, 0 }, | ||
140 | { 0, 5, 69, 54, 0 }, | ||
141 | { 0, 64, 64, 0, 0 }, | ||
142 | { 0, 54, 69, 5, 0 }, | ||
143 | { 0, 45, 72, 11, 0 }, | ||
144 | { 0, 35, 74, 19, 0 }, | ||
145 | }; | ||
146 | |||
147 | static const struct dispc_coef coef3_M32[8] = { | ||
148 | { 0, 27, 74, 27, 0 }, | ||
149 | { 0, 19, 73, 36, 0 }, | ||
150 | { 0, 12, 71, 45, 0 }, | ||
151 | { 0, 6, 68, 54, 0 }, | ||
152 | { 0, 64, 64, 0, 0 }, | ||
153 | { 0, 54, 68, 6, 0 }, | ||
154 | { 0, 45, 71, 12, 0 }, | ||
155 | { 0, 36, 73, 19, 0 }, | ||
156 | }; | ||
157 | |||
158 | static const struct dispc_coef coef5_M8[8] = { | ||
159 | { 0, 0, 128, 0, 0 }, | ||
160 | { -2, 14, 125, -10, 1 }, | ||
161 | { -6, 33, 114, -15, 2 }, | ||
162 | { -10, 55, 98, -16, 1 }, | ||
163 | { 0, -14, 78, 78, -14 }, | ||
164 | { 1, -16, 98, 55, -10 }, | ||
165 | { 2, -15, 114, 33, -6 }, | ||
166 | { 1, -10, 125, 14, -2 }, | ||
167 | }; | ||
168 | |||
169 | static const struct dispc_coef coef5_M9[8] = { | ||
170 | { -3, 10, 114, 10, -3 }, | ||
171 | { -6, 24, 110, 0, -1 }, | ||
172 | { -8, 40, 103, -7, 0 }, | ||
173 | { -11, 58, 91, -11, 1 }, | ||
174 | { 0, -12, 76, 76, -12 }, | ||
175 | { 1, -11, 91, 58, -11 }, | ||
176 | { 0, -7, 103, 40, -8 }, | ||
177 | { -1, 0, 111, 24, -6 }, | ||
178 | }; | ||
179 | |||
180 | static const struct dispc_coef coef5_M10[8] = { | ||
181 | { -4, 18, 100, 18, -4 }, | ||
182 | { -6, 30, 99, 8, -3 }, | ||
183 | { -8, 44, 93, 0, -1 }, | ||
184 | { -9, 58, 84, -5, 0 }, | ||
185 | { 0, -8, 72, 72, -8 }, | ||
186 | { 0, -5, 84, 58, -9 }, | ||
187 | { -1, 0, 93, 44, -8 }, | ||
188 | { -3, 8, 99, 30, -6 }, | ||
189 | }; | ||
190 | |||
191 | static const struct dispc_coef coef5_M11[8] = { | ||
192 | { -5, 23, 92, 23, -5 }, | ||
193 | { -6, 34, 90, 13, -3 }, | ||
194 | { -6, 45, 85, 6, -2 }, | ||
195 | { -6, 57, 78, 0, -1 }, | ||
196 | { 0, -4, 68, 68, -4 }, | ||
197 | { -1, 0, 78, 57, -6 }, | ||
198 | { -2, 6, 85, 45, -6 }, | ||
199 | { -3, 13, 90, 34, -6 }, | ||
200 | }; | ||
201 | |||
202 | static const struct dispc_coef coef5_M12[8] = { | ||
203 | { -4, 26, 84, 26, -4 }, | ||
204 | { -5, 36, 82, 18, -3 }, | ||
205 | { -4, 46, 78, 10, -2 }, | ||
206 | { -3, 55, 72, 5, -1 }, | ||
207 | { 0, 0, 64, 64, 0 }, | ||
208 | { -1, 5, 72, 55, -3 }, | ||
209 | { -2, 10, 78, 46, -4 }, | ||
210 | { -3, 18, 82, 36, -5 }, | ||
211 | }; | ||
212 | |||
213 | static const struct dispc_coef coef5_M13[8] = { | ||
214 | { -3, 28, 78, 28, -3 }, | ||
215 | { -3, 37, 76, 21, -3 }, | ||
216 | { -2, 45, 73, 14, -2 }, | ||
217 | { 0, 53, 68, 8, -1 }, | ||
218 | { 0, 3, 61, 61, 3 }, | ||
219 | { -1, 8, 68, 53, 0 }, | ||
220 | { -2, 14, 73, 45, -2 }, | ||
221 | { -3, 21, 76, 37, -3 }, | ||
222 | }; | ||
223 | |||
224 | static const struct dispc_coef coef5_M14[8] = { | ||
225 | { -2, 30, 72, 30, -2 }, | ||
226 | { -1, 37, 71, 23, -2 }, | ||
227 | { 0, 45, 69, 16, -2 }, | ||
228 | { 3, 52, 64, 10, -1 }, | ||
229 | { 0, 6, 58, 58, 6 }, | ||
230 | { -1, 10, 64, 52, 3 }, | ||
231 | { -2, 16, 69, 45, 0 }, | ||
232 | { -2, 23, 71, 37, -1 }, | ||
233 | }; | ||
234 | |||
235 | static const struct dispc_coef coef5_M16[8] = { | ||
236 | { 0, 31, 66, 31, 0 }, | ||
237 | { 1, 38, 65, 25, -1 }, | ||
238 | { 3, 44, 62, 20, -1 }, | ||
239 | { 6, 49, 59, 14, 0 }, | ||
240 | { 0, 10, 54, 54, 10 }, | ||
241 | { 0, 14, 59, 49, 6 }, | ||
242 | { -1, 20, 62, 44, 3 }, | ||
243 | { -1, 25, 65, 38, 1 }, | ||
244 | }; | ||
245 | |||
246 | static const struct dispc_coef coef5_M19[8] = { | ||
247 | { 3, 32, 58, 32, 3 }, | ||
248 | { 4, 38, 58, 27, 1 }, | ||
249 | { 7, 42, 55, 23, 1 }, | ||
250 | { 10, 46, 54, 18, 0 }, | ||
251 | { 0, 14, 50, 50, 14 }, | ||
252 | { 0, 18, 54, 46, 10 }, | ||
253 | { 1, 23, 55, 42, 7 }, | ||
254 | { 1, 27, 58, 38, 4 }, | ||
255 | }; | ||
256 | |||
257 | static const struct dispc_coef coef5_M22[8] = { | ||
258 | { 4, 33, 54, 33, 4 }, | ||
259 | { 6, 37, 54, 28, 3 }, | ||
260 | { 9, 41, 53, 24, 1 }, | ||
261 | { 12, 45, 51, 20, 0 }, | ||
262 | { 0, 16, 48, 48, 16 }, | ||
263 | { 0, 20, 51, 45, 12 }, | ||
264 | { 1, 24, 53, 41, 9 }, | ||
265 | { 3, 28, 54, 37, 6 }, | ||
266 | }; | ||
267 | |||
268 | static const struct dispc_coef coef5_M26[8] = { | ||
269 | { 6, 33, 50, 33, 6 }, | ||
270 | { 8, 36, 51, 29, 4 }, | ||
271 | { 11, 40, 50, 25, 2 }, | ||
272 | { 14, 43, 48, 22, 1 }, | ||
273 | { 0, 18, 46, 46, 18 }, | ||
274 | { 1, 22, 48, 43, 14 }, | ||
275 | { 2, 25, 50, 40, 11 }, | ||
276 | { 4, 29, 51, 36, 8 }, | ||
277 | }; | ||
278 | |||
279 | static const struct dispc_coef coef5_M32[8] = { | ||
280 | { 7, 33, 48, 33, 7 }, | ||
281 | { 10, 36, 48, 29, 5 }, | ||
282 | { 13, 39, 47, 26, 3 }, | ||
283 | { 16, 42, 46, 23, 1 }, | ||
284 | { 0, 19, 45, 45, 19 }, | ||
285 | { 1, 23, 46, 42, 16 }, | ||
286 | { 3, 26, 47, 39, 13 }, | ||
287 | { 5, 29, 48, 36, 10 }, | ||
288 | }; | ||
289 | |||
290 | const struct dispc_coef *dispc_ovl_get_scale_coef(int inc, int five_taps) | ||
291 | { | ||
292 | int i; | ||
293 | static const struct { | ||
294 | int Mmin; | ||
295 | int Mmax; | ||
296 | const struct dispc_coef *coef_3; | ||
297 | const struct dispc_coef *coef_5; | ||
298 | } coefs[] = { | ||
299 | { 27, 32, coef3_M32, coef5_M32 }, | ||
300 | { 23, 26, coef3_M26, coef5_M26 }, | ||
301 | { 20, 22, coef3_M22, coef5_M22 }, | ||
302 | { 17, 19, coef3_M19, coef5_M19 }, | ||
303 | { 15, 16, coef3_M16, coef5_M16 }, | ||
304 | { 14, 14, coef3_M14, coef5_M14 }, | ||
305 | { 13, 13, coef3_M13, coef5_M13 }, | ||
306 | { 12, 12, coef3_M12, coef5_M12 }, | ||
307 | { 11, 11, coef3_M11, coef5_M11 }, | ||
308 | { 10, 10, coef3_M10, coef5_M10 }, | ||
309 | { 9, 9, coef3_M9, coef5_M9 }, | ||
310 | { 4, 8, coef3_M8, coef5_M8 }, | ||
311 | /* | ||
312 | * When upscaling more than two times, blockiness and outlines | ||
313 | * around the image are observed when M8 tables are used. M11, | ||
314 | * M16 and M19 tables are used to prevent this. | ||
315 | */ | ||
316 | { 3, 3, coef3_M11, coef5_M11 }, | ||
317 | { 2, 2, coef3_M16, coef5_M16 }, | ||
318 | { 0, 1, coef3_M19, coef5_M19 }, | ||
319 | }; | ||
320 | |||
321 | inc /= 128; | ||
322 | for (i = 0; i < ARRAY_LEN(coefs); ++i) | ||
323 | if (inc >= coefs[i].Mmin && inc <= coefs[i].Mmax) | ||
324 | return five_taps ? coefs[i].coef_5 : coefs[i].coef_3; | ||
325 | return NULL; | ||
326 | } | ||
diff --git a/drivers/video/omap2/dss/dpi.c b/drivers/video/omap2/dss/dpi.c index 976ac23dcd0c..395d658a94fc 100644 --- a/drivers/video/omap2/dss/dpi.c +++ b/drivers/video/omap2/dss/dpi.c | |||
@@ -223,10 +223,13 @@ int omapdss_dpi_display_enable(struct omap_dss_device *dssdev) | |||
223 | 223 | ||
224 | mdelay(2); | 224 | mdelay(2); |
225 | 225 | ||
226 | dssdev->manager->enable(dssdev->manager); | 226 | r = dss_mgr_enable(dssdev->manager); |
227 | if (r) | ||
228 | goto err_mgr_enable; | ||
227 | 229 | ||
228 | return 0; | 230 | return 0; |
229 | 231 | ||
232 | err_mgr_enable: | ||
230 | err_set_mode: | 233 | err_set_mode: |
231 | if (dpi_use_dsi_pll(dssdev)) | 234 | if (dpi_use_dsi_pll(dssdev)) |
232 | dsi_pll_uninit(dpi.dsidev, true); | 235 | dsi_pll_uninit(dpi.dsidev, true); |
@@ -249,7 +252,7 @@ EXPORT_SYMBOL(omapdss_dpi_display_enable); | |||
249 | 252 | ||
250 | void omapdss_dpi_display_disable(struct omap_dss_device *dssdev) | 253 | void omapdss_dpi_display_disable(struct omap_dss_device *dssdev) |
251 | { | 254 | { |
252 | dssdev->manager->disable(dssdev->manager); | 255 | dss_mgr_disable(dssdev->manager); |
253 | 256 | ||
254 | if (dpi_use_dsi_pll(dssdev)) { | 257 | if (dpi_use_dsi_pll(dssdev)) { |
255 | dss_select_dispc_clk_source(OMAP_DSS_CLK_SRC_FCK); | 258 | dss_select_dispc_clk_source(OMAP_DSS_CLK_SRC_FCK); |
diff --git a/drivers/video/omap2/dss/dsi.c b/drivers/video/omap2/dss/dsi.c index 46f37883e499..d4d676c82c12 100644 --- a/drivers/video/omap2/dss/dsi.c +++ b/drivers/video/omap2/dss/dsi.c | |||
@@ -203,6 +203,21 @@ struct dsi_reg { u16 idx; }; | |||
203 | typedef void (*omap_dsi_isr_t) (void *arg, u32 mask); | 203 | typedef void (*omap_dsi_isr_t) (void *arg, u32 mask); |
204 | 204 | ||
205 | #define DSI_MAX_NR_ISRS 2 | 205 | #define DSI_MAX_NR_ISRS 2 |
206 | #define DSI_MAX_NR_LANES 5 | ||
207 | |||
208 | enum dsi_lane_function { | ||
209 | DSI_LANE_UNUSED = 0, | ||
210 | DSI_LANE_CLK, | ||
211 | DSI_LANE_DATA1, | ||
212 | DSI_LANE_DATA2, | ||
213 | DSI_LANE_DATA3, | ||
214 | DSI_LANE_DATA4, | ||
215 | }; | ||
216 | |||
217 | struct dsi_lane_config { | ||
218 | enum dsi_lane_function function; | ||
219 | u8 polarity; | ||
220 | }; | ||
206 | 221 | ||
207 | struct dsi_isr_data { | 222 | struct dsi_isr_data { |
208 | omap_dsi_isr_t isr; | 223 | omap_dsi_isr_t isr; |
@@ -223,24 +238,6 @@ enum dsi_vc_source { | |||
223 | DSI_VC_SOURCE_VP, | 238 | DSI_VC_SOURCE_VP, |
224 | }; | 239 | }; |
225 | 240 | ||
226 | enum dsi_lane { | ||
227 | DSI_CLK_P = 1 << 0, | ||
228 | DSI_CLK_N = 1 << 1, | ||
229 | DSI_DATA1_P = 1 << 2, | ||
230 | DSI_DATA1_N = 1 << 3, | ||
231 | DSI_DATA2_P = 1 << 4, | ||
232 | DSI_DATA2_N = 1 << 5, | ||
233 | DSI_DATA3_P = 1 << 6, | ||
234 | DSI_DATA3_N = 1 << 7, | ||
235 | DSI_DATA4_P = 1 << 8, | ||
236 | DSI_DATA4_N = 1 << 9, | ||
237 | }; | ||
238 | |||
239 | struct dsi_update_region { | ||
240 | u16 x, y, w, h; | ||
241 | struct omap_dss_device *device; | ||
242 | }; | ||
243 | |||
244 | struct dsi_irq_stats { | 241 | struct dsi_irq_stats { |
245 | unsigned long last_reset; | 242 | unsigned long last_reset; |
246 | unsigned irq_count; | 243 | unsigned irq_count; |
@@ -290,7 +287,9 @@ struct dsi_data { | |||
290 | struct dsi_isr_tables isr_tables_copy; | 287 | struct dsi_isr_tables isr_tables_copy; |
291 | 288 | ||
292 | int update_channel; | 289 | int update_channel; |
293 | struct dsi_update_region update_region; | 290 | #ifdef DEBUG |
291 | unsigned update_bytes; | ||
292 | #endif | ||
294 | 293 | ||
295 | bool te_enabled; | 294 | bool te_enabled; |
296 | bool ulps_enabled; | 295 | bool ulps_enabled; |
@@ -327,7 +326,10 @@ struct dsi_data { | |||
327 | unsigned long fint_min, fint_max; | 326 | unsigned long fint_min, fint_max; |
328 | unsigned long lpdiv_max; | 327 | unsigned long lpdiv_max; |
329 | 328 | ||
330 | int num_data_lanes; | 329 | unsigned num_lanes_supported; |
330 | |||
331 | struct dsi_lane_config lanes[DSI_MAX_NR_LANES]; | ||
332 | unsigned num_lanes_used; | ||
331 | 333 | ||
332 | unsigned scp_clk_refcount; | 334 | unsigned scp_clk_refcount; |
333 | }; | 335 | }; |
@@ -413,14 +415,29 @@ static void dsi_completion_handler(void *data, u32 mask) | |||
413 | static inline int wait_for_bit_change(struct platform_device *dsidev, | 415 | static inline int wait_for_bit_change(struct platform_device *dsidev, |
414 | const struct dsi_reg idx, int bitnum, int value) | 416 | const struct dsi_reg idx, int bitnum, int value) |
415 | { | 417 | { |
416 | int t = 100000; | 418 | unsigned long timeout; |
419 | ktime_t wait; | ||
420 | int t; | ||
417 | 421 | ||
418 | while (REG_GET(dsidev, idx, bitnum, bitnum) != value) { | 422 | /* first busyloop to see if the bit changes right away */ |
419 | if (--t == 0) | 423 | t = 100; |
420 | return !value; | 424 | while (t-- > 0) { |
425 | if (REG_GET(dsidev, idx, bitnum, bitnum) == value) | ||
426 | return value; | ||
421 | } | 427 | } |
422 | 428 | ||
423 | return value; | 429 | /* then loop for 500ms, sleeping for 1ms in between */ |
430 | timeout = jiffies + msecs_to_jiffies(500); | ||
431 | while (time_before(jiffies, timeout)) { | ||
432 | if (REG_GET(dsidev, idx, bitnum, bitnum) == value) | ||
433 | return value; | ||
434 | |||
435 | wait = ns_to_ktime(1000 * 1000); | ||
436 | set_current_state(TASK_UNINTERRUPTIBLE); | ||
437 | schedule_hrtimeout(&wait, HRTIMER_MODE_REL); | ||
438 | } | ||
439 | |||
440 | return !value; | ||
424 | } | 441 | } |
425 | 442 | ||
426 | u8 dsi_get_pixel_size(enum omap_dss_dsi_pixel_format fmt) | 443 | u8 dsi_get_pixel_size(enum omap_dss_dsi_pixel_format fmt) |
@@ -454,7 +471,6 @@ static void dsi_perf_mark_start(struct platform_device *dsidev) | |||
454 | static void dsi_perf_show(struct platform_device *dsidev, const char *name) | 471 | static void dsi_perf_show(struct platform_device *dsidev, const char *name) |
455 | { | 472 | { |
456 | struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); | 473 | struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); |
457 | struct omap_dss_device *dssdev = dsi->update_region.device; | ||
458 | ktime_t t, setup_time, trans_time; | 474 | ktime_t t, setup_time, trans_time; |
459 | u32 total_bytes; | 475 | u32 total_bytes; |
460 | u32 setup_us, trans_us, total_us; | 476 | u32 setup_us, trans_us, total_us; |
@@ -476,9 +492,7 @@ static void dsi_perf_show(struct platform_device *dsidev, const char *name) | |||
476 | 492 | ||
477 | total_us = setup_us + trans_us; | 493 | total_us = setup_us + trans_us; |
478 | 494 | ||
479 | total_bytes = dsi->update_region.w * | 495 | total_bytes = dsi->update_bytes; |
480 | dsi->update_region.h * | ||
481 | dsi_get_pixel_size(dssdev->panel.dsi_pix_fmt) / 8; | ||
482 | 496 | ||
483 | printk(KERN_INFO "DSI(%s): %u us + %u us = %u us (%uHz), " | 497 | printk(KERN_INFO "DSI(%s): %u us + %u us = %u us (%uHz), " |
484 | "%u bytes, %u kbytes/sec\n", | 498 | "%u bytes, %u kbytes/sec\n", |
@@ -1720,17 +1734,19 @@ static void dsi_dump_dsidev_clocks(struct platform_device *dsidev, | |||
1720 | seq_printf(s, "CLKIN4DDR\t%-16luregm %u\n", | 1734 | seq_printf(s, "CLKIN4DDR\t%-16luregm %u\n", |
1721 | cinfo->clkin4ddr, cinfo->regm); | 1735 | cinfo->clkin4ddr, cinfo->regm); |
1722 | 1736 | ||
1723 | seq_printf(s, "%s (%s)\t%-16luregm_dispc %u\t(%s)\n", | 1737 | seq_printf(s, "DSI_PLL_HSDIV_DISPC (%s)\t%-16luregm_dispc %u\t(%s)\n", |
1724 | dss_get_generic_clk_source_name(dispc_clk_src), | 1738 | dss_feat_get_clk_source_name(dsi_module == 0 ? |
1725 | dss_feat_get_clk_source_name(dispc_clk_src), | 1739 | OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC : |
1740 | OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DISPC), | ||
1726 | cinfo->dsi_pll_hsdiv_dispc_clk, | 1741 | cinfo->dsi_pll_hsdiv_dispc_clk, |
1727 | cinfo->regm_dispc, | 1742 | cinfo->regm_dispc, |
1728 | dispc_clk_src == OMAP_DSS_CLK_SRC_FCK ? | 1743 | dispc_clk_src == OMAP_DSS_CLK_SRC_FCK ? |
1729 | "off" : "on"); | 1744 | "off" : "on"); |
1730 | 1745 | ||
1731 | seq_printf(s, "%s (%s)\t%-16luregm_dsi %u\t(%s)\n", | 1746 | seq_printf(s, "DSI_PLL_HSDIV_DSI (%s)\t%-16luregm_dsi %u\t(%s)\n", |
1732 | dss_get_generic_clk_source_name(dsi_clk_src), | 1747 | dss_feat_get_clk_source_name(dsi_module == 0 ? |
1733 | dss_feat_get_clk_source_name(dsi_clk_src), | 1748 | OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DSI : |
1749 | OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DSI), | ||
1734 | cinfo->dsi_pll_hsdiv_dsi_clk, | 1750 | cinfo->dsi_pll_hsdiv_dsi_clk, |
1735 | cinfo->regm_dsi, | 1751 | cinfo->regm_dsi, |
1736 | dsi_clk_src == OMAP_DSS_CLK_SRC_FCK ? | 1752 | dsi_clk_src == OMAP_DSS_CLK_SRC_FCK ? |
@@ -2029,34 +2045,6 @@ static int dsi_cio_power(struct platform_device *dsidev, | |||
2029 | return 0; | 2045 | return 0; |
2030 | } | 2046 | } |
2031 | 2047 | ||
2032 | /* Number of data lanes present on DSI interface */ | ||
2033 | static inline int dsi_get_num_data_lanes(struct platform_device *dsidev) | ||
2034 | { | ||
2035 | /* DSI on OMAP3 doesn't have register DSI_GNQ, set number | ||
2036 | * of data lanes as 2 by default */ | ||
2037 | if (dss_has_feature(FEAT_DSI_GNQ)) | ||
2038 | return REG_GET(dsidev, DSI_GNQ, 11, 9); /* NB_DATA_LANES */ | ||
2039 | else | ||
2040 | return 2; | ||
2041 | } | ||
2042 | |||
2043 | /* Number of data lanes used by the dss device */ | ||
2044 | static inline int dsi_get_num_data_lanes_dssdev(struct omap_dss_device *dssdev) | ||
2045 | { | ||
2046 | int num_data_lanes = 0; | ||
2047 | |||
2048 | if (dssdev->phy.dsi.data1_lane != 0) | ||
2049 | num_data_lanes++; | ||
2050 | if (dssdev->phy.dsi.data2_lane != 0) | ||
2051 | num_data_lanes++; | ||
2052 | if (dssdev->phy.dsi.data3_lane != 0) | ||
2053 | num_data_lanes++; | ||
2054 | if (dssdev->phy.dsi.data4_lane != 0) | ||
2055 | num_data_lanes++; | ||
2056 | |||
2057 | return num_data_lanes; | ||
2058 | } | ||
2059 | |||
2060 | static unsigned dsi_get_line_buf_size(struct platform_device *dsidev) | 2048 | static unsigned dsi_get_line_buf_size(struct platform_device *dsidev) |
2061 | { | 2049 | { |
2062 | int val; | 2050 | int val; |
@@ -2088,59 +2076,112 @@ static unsigned dsi_get_line_buf_size(struct platform_device *dsidev) | |||
2088 | } | 2076 | } |
2089 | } | 2077 | } |
2090 | 2078 | ||
2091 | static void dsi_set_lane_config(struct omap_dss_device *dssdev) | 2079 | static int dsi_parse_lane_config(struct omap_dss_device *dssdev) |
2092 | { | 2080 | { |
2093 | struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); | 2081 | struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); |
2094 | u32 r; | 2082 | struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); |
2095 | int num_data_lanes_dssdev = dsi_get_num_data_lanes_dssdev(dssdev); | 2083 | u8 lanes[DSI_MAX_NR_LANES]; |
2084 | u8 polarities[DSI_MAX_NR_LANES]; | ||
2085 | int num_lanes, i; | ||
2086 | |||
2087 | static const enum dsi_lane_function functions[] = { | ||
2088 | DSI_LANE_CLK, | ||
2089 | DSI_LANE_DATA1, | ||
2090 | DSI_LANE_DATA2, | ||
2091 | DSI_LANE_DATA3, | ||
2092 | DSI_LANE_DATA4, | ||
2093 | }; | ||
2094 | |||
2095 | lanes[0] = dssdev->phy.dsi.clk_lane; | ||
2096 | lanes[1] = dssdev->phy.dsi.data1_lane; | ||
2097 | lanes[2] = dssdev->phy.dsi.data2_lane; | ||
2098 | lanes[3] = dssdev->phy.dsi.data3_lane; | ||
2099 | lanes[4] = dssdev->phy.dsi.data4_lane; | ||
2100 | polarities[0] = dssdev->phy.dsi.clk_pol; | ||
2101 | polarities[1] = dssdev->phy.dsi.data1_pol; | ||
2102 | polarities[2] = dssdev->phy.dsi.data2_pol; | ||
2103 | polarities[3] = dssdev->phy.dsi.data3_pol; | ||
2104 | polarities[4] = dssdev->phy.dsi.data4_pol; | ||
2096 | 2105 | ||
2097 | int clk_lane = dssdev->phy.dsi.clk_lane; | 2106 | num_lanes = 0; |
2098 | int data1_lane = dssdev->phy.dsi.data1_lane; | 2107 | |
2099 | int data2_lane = dssdev->phy.dsi.data2_lane; | 2108 | for (i = 0; i < dsi->num_lanes_supported; ++i) |
2100 | int clk_pol = dssdev->phy.dsi.clk_pol; | 2109 | dsi->lanes[i].function = DSI_LANE_UNUSED; |
2101 | int data1_pol = dssdev->phy.dsi.data1_pol; | 2110 | |
2102 | int data2_pol = dssdev->phy.dsi.data2_pol; | 2111 | for (i = 0; i < dsi->num_lanes_supported; ++i) { |
2112 | int num; | ||
2113 | |||
2114 | if (lanes[i] == DSI_LANE_UNUSED) | ||
2115 | break; | ||
2116 | |||
2117 | num = lanes[i] - 1; | ||
2118 | |||
2119 | if (num >= dsi->num_lanes_supported) | ||
2120 | return -EINVAL; | ||
2121 | |||
2122 | if (dsi->lanes[num].function != DSI_LANE_UNUSED) | ||
2123 | return -EINVAL; | ||
2124 | |||
2125 | dsi->lanes[num].function = functions[i]; | ||
2126 | dsi->lanes[num].polarity = polarities[i]; | ||
2127 | num_lanes++; | ||
2128 | } | ||
2129 | |||
2130 | if (num_lanes < 2 || num_lanes > dsi->num_lanes_supported) | ||
2131 | return -EINVAL; | ||
2132 | |||
2133 | dsi->num_lanes_used = num_lanes; | ||
2134 | |||
2135 | return 0; | ||
2136 | } | ||
2137 | |||
2138 | static int dsi_set_lane_config(struct omap_dss_device *dssdev) | ||
2139 | { | ||
2140 | struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); | ||
2141 | struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); | ||
2142 | static const u8 offsets[] = { 0, 4, 8, 12, 16 }; | ||
2143 | static const enum dsi_lane_function functions[] = { | ||
2144 | DSI_LANE_CLK, | ||
2145 | DSI_LANE_DATA1, | ||
2146 | DSI_LANE_DATA2, | ||
2147 | DSI_LANE_DATA3, | ||
2148 | DSI_LANE_DATA4, | ||
2149 | }; | ||
2150 | u32 r; | ||
2151 | int i; | ||
2103 | 2152 | ||
2104 | r = dsi_read_reg(dsidev, DSI_COMPLEXIO_CFG1); | 2153 | r = dsi_read_reg(dsidev, DSI_COMPLEXIO_CFG1); |
2105 | r = FLD_MOD(r, clk_lane, 2, 0); | 2154 | |
2106 | r = FLD_MOD(r, clk_pol, 3, 3); | 2155 | for (i = 0; i < dsi->num_lanes_used; ++i) { |
2107 | r = FLD_MOD(r, data1_lane, 6, 4); | 2156 | unsigned offset = offsets[i]; |
2108 | r = FLD_MOD(r, data1_pol, 7, 7); | 2157 | unsigned polarity, lane_number; |
2109 | r = FLD_MOD(r, data2_lane, 10, 8); | 2158 | unsigned t; |
2110 | r = FLD_MOD(r, data2_pol, 11, 11); | 2159 | |
2111 | if (num_data_lanes_dssdev > 2) { | 2160 | for (t = 0; t < dsi->num_lanes_supported; ++t) |
2112 | int data3_lane = dssdev->phy.dsi.data3_lane; | 2161 | if (dsi->lanes[t].function == functions[i]) |
2113 | int data3_pol = dssdev->phy.dsi.data3_pol; | 2162 | break; |
2114 | 2163 | ||
2115 | r = FLD_MOD(r, data3_lane, 14, 12); | 2164 | if (t == dsi->num_lanes_supported) |
2116 | r = FLD_MOD(r, data3_pol, 15, 15); | 2165 | return -EINVAL; |
2166 | |||
2167 | lane_number = t; | ||
2168 | polarity = dsi->lanes[t].polarity; | ||
2169 | |||
2170 | r = FLD_MOD(r, lane_number + 1, offset + 2, offset); | ||
2171 | r = FLD_MOD(r, polarity, offset + 3, offset + 3); | ||
2117 | } | 2172 | } |
2118 | if (num_data_lanes_dssdev > 3) { | ||
2119 | int data4_lane = dssdev->phy.dsi.data4_lane; | ||
2120 | int data4_pol = dssdev->phy.dsi.data4_pol; | ||
2121 | 2173 | ||
2122 | r = FLD_MOD(r, data4_lane, 18, 16); | 2174 | /* clear the unused lanes */ |
2123 | r = FLD_MOD(r, data4_pol, 19, 19); | 2175 | for (; i < dsi->num_lanes_supported; ++i) { |
2176 | unsigned offset = offsets[i]; | ||
2177 | |||
2178 | r = FLD_MOD(r, 0, offset + 2, offset); | ||
2179 | r = FLD_MOD(r, 0, offset + 3, offset + 3); | ||
2124 | } | 2180 | } |
2125 | dsi_write_reg(dsidev, DSI_COMPLEXIO_CFG1, r); | ||
2126 | 2181 | ||
2127 | /* The configuration of the DSI complex I/O (number of data lanes, | 2182 | dsi_write_reg(dsidev, DSI_COMPLEXIO_CFG1, r); |
2128 | position, differential order) should not be changed while | ||
2129 | DSS.DSI_CLK_CRTRL[20] LP_CLK_ENABLE bit is set to 1. In order for | ||
2130 | the hardware to take into account a new configuration of the complex | ||
2131 | I/O (done in DSS.DSI_COMPLEXIO_CFG1 register), it is recommended to | ||
2132 | follow this sequence: First set the DSS.DSI_CTRL[0] IF_EN bit to 1, | ||
2133 | then reset the DSS.DSI_CTRL[0] IF_EN to 0, then set | ||
2134 | DSS.DSI_CLK_CTRL[20] LP_CLK_ENABLE to 1 and finally set again the | ||
2135 | DSS.DSI_CTRL[0] IF_EN bit to 1. If the sequence is not followed, the | ||
2136 | DSI complex I/O configuration is unknown. */ | ||
2137 | 2183 | ||
2138 | /* | 2184 | return 0; |
2139 | REG_FLD_MOD(dsidev, DSI_CTRL, 1, 0, 0); | ||
2140 | REG_FLD_MOD(dsidev, DSI_CTRL, 0, 0, 0); | ||
2141 | REG_FLD_MOD(dsidev, DSI_CLK_CTRL, 1, 20, 20); | ||
2142 | REG_FLD_MOD(dsidev, DSI_CTRL, 1, 0, 0); | ||
2143 | */ | ||
2144 | } | 2185 | } |
2145 | 2186 | ||
2146 | static inline unsigned ns2ddr(struct platform_device *dsidev, unsigned ns) | 2187 | static inline unsigned ns2ddr(struct platform_device *dsidev, unsigned ns) |
@@ -2230,49 +2271,28 @@ static void dsi_cio_timings(struct platform_device *dsidev) | |||
2230 | dsi_write_reg(dsidev, DSI_DSIPHY_CFG2, r); | 2271 | dsi_write_reg(dsidev, DSI_DSIPHY_CFG2, r); |
2231 | } | 2272 | } |
2232 | 2273 | ||
2274 | /* lane masks have lane 0 at lsb. mask_p for positive lines, n for negative */ | ||
2233 | static void dsi_cio_enable_lane_override(struct omap_dss_device *dssdev, | 2275 | static void dsi_cio_enable_lane_override(struct omap_dss_device *dssdev, |
2234 | enum dsi_lane lanes) | 2276 | unsigned mask_p, unsigned mask_n) |
2235 | { | 2277 | { |
2236 | struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); | 2278 | struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); |
2237 | struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); | 2279 | struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); |
2238 | int clk_lane = dssdev->phy.dsi.clk_lane; | 2280 | int i; |
2239 | int data1_lane = dssdev->phy.dsi.data1_lane; | 2281 | u32 l; |
2240 | int data2_lane = dssdev->phy.dsi.data2_lane; | 2282 | u8 lptxscp_start = dsi->num_lanes_supported == 3 ? 22 : 26; |
2241 | int data3_lane = dssdev->phy.dsi.data3_lane; | 2283 | |
2242 | int data4_lane = dssdev->phy.dsi.data4_lane; | 2284 | l = 0; |
2243 | int clk_pol = dssdev->phy.dsi.clk_pol; | 2285 | |
2244 | int data1_pol = dssdev->phy.dsi.data1_pol; | 2286 | for (i = 0; i < dsi->num_lanes_supported; ++i) { |
2245 | int data2_pol = dssdev->phy.dsi.data2_pol; | 2287 | unsigned p = dsi->lanes[i].polarity; |
2246 | int data3_pol = dssdev->phy.dsi.data3_pol; | 2288 | |
2247 | int data4_pol = dssdev->phy.dsi.data4_pol; | 2289 | if (mask_p & (1 << i)) |
2248 | 2290 | l |= 1 << (i * 2 + (p ? 0 : 1)); | |
2249 | u32 l = 0; | 2291 | |
2250 | u8 lptxscp_start = dsi->num_data_lanes == 2 ? 22 : 26; | 2292 | if (mask_n & (1 << i)) |
2251 | 2293 | l |= 1 << (i * 2 + (p ? 1 : 0)); | |
2252 | if (lanes & DSI_CLK_P) | 2294 | } |
2253 | l |= 1 << ((clk_lane - 1) * 2 + (clk_pol ? 0 : 1)); | 2295 | |
2254 | if (lanes & DSI_CLK_N) | ||
2255 | l |= 1 << ((clk_lane - 1) * 2 + (clk_pol ? 1 : 0)); | ||
2256 | |||
2257 | if (lanes & DSI_DATA1_P) | ||
2258 | l |= 1 << ((data1_lane - 1) * 2 + (data1_pol ? 0 : 1)); | ||
2259 | if (lanes & DSI_DATA1_N) | ||
2260 | l |= 1 << ((data1_lane - 1) * 2 + (data1_pol ? 1 : 0)); | ||
2261 | |||
2262 | if (lanes & DSI_DATA2_P) | ||
2263 | l |= 1 << ((data2_lane - 1) * 2 + (data2_pol ? 0 : 1)); | ||
2264 | if (lanes & DSI_DATA2_N) | ||
2265 | l |= 1 << ((data2_lane - 1) * 2 + (data2_pol ? 1 : 0)); | ||
2266 | |||
2267 | if (lanes & DSI_DATA3_P) | ||
2268 | l |= 1 << ((data3_lane - 1) * 2 + (data3_pol ? 0 : 1)); | ||
2269 | if (lanes & DSI_DATA3_N) | ||
2270 | l |= 1 << ((data3_lane - 1) * 2 + (data3_pol ? 1 : 0)); | ||
2271 | |||
2272 | if (lanes & DSI_DATA4_P) | ||
2273 | l |= 1 << ((data4_lane - 1) * 2 + (data4_pol ? 0 : 1)); | ||
2274 | if (lanes & DSI_DATA4_N) | ||
2275 | l |= 1 << ((data4_lane - 1) * 2 + (data4_pol ? 1 : 0)); | ||
2276 | /* | 2296 | /* |
2277 | * Bits in REGLPTXSCPDAT4TO0DXDY: | 2297 | * Bits in REGLPTXSCPDAT4TO0DXDY: |
2278 | * 17: DY0 18: DX0 | 2298 | * 17: DY0 18: DX0 |
@@ -2305,51 +2325,40 @@ static void dsi_cio_disable_lane_override(struct platform_device *dsidev) | |||
2305 | static int dsi_cio_wait_tx_clk_esc_reset(struct omap_dss_device *dssdev) | 2325 | static int dsi_cio_wait_tx_clk_esc_reset(struct omap_dss_device *dssdev) |
2306 | { | 2326 | { |
2307 | struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); | 2327 | struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); |
2308 | int t; | 2328 | struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); |
2309 | int bits[3]; | 2329 | int t, i; |
2310 | bool in_use[3]; | 2330 | bool in_use[DSI_MAX_NR_LANES]; |
2311 | 2331 | static const u8 offsets_old[] = { 28, 27, 26 }; | |
2312 | if (dss_has_feature(FEAT_DSI_REVERSE_TXCLKESC)) { | 2332 | static const u8 offsets_new[] = { 24, 25, 26, 27, 28 }; |
2313 | bits[0] = 28; | 2333 | const u8 *offsets; |
2314 | bits[1] = 27; | 2334 | |
2315 | bits[2] = 26; | 2335 | if (dss_has_feature(FEAT_DSI_REVERSE_TXCLKESC)) |
2316 | } else { | 2336 | offsets = offsets_old; |
2317 | bits[0] = 24; | 2337 | else |
2318 | bits[1] = 25; | 2338 | offsets = offsets_new; |
2319 | bits[2] = 26; | ||
2320 | } | ||
2321 | |||
2322 | in_use[0] = false; | ||
2323 | in_use[1] = false; | ||
2324 | in_use[2] = false; | ||
2325 | 2339 | ||
2326 | if (dssdev->phy.dsi.clk_lane != 0) | 2340 | for (i = 0; i < dsi->num_lanes_supported; ++i) |
2327 | in_use[dssdev->phy.dsi.clk_lane - 1] = true; | 2341 | in_use[i] = dsi->lanes[i].function != DSI_LANE_UNUSED; |
2328 | if (dssdev->phy.dsi.data1_lane != 0) | ||
2329 | in_use[dssdev->phy.dsi.data1_lane - 1] = true; | ||
2330 | if (dssdev->phy.dsi.data2_lane != 0) | ||
2331 | in_use[dssdev->phy.dsi.data2_lane - 1] = true; | ||
2332 | 2342 | ||
2333 | t = 100000; | 2343 | t = 100000; |
2334 | while (true) { | 2344 | while (true) { |
2335 | u32 l; | 2345 | u32 l; |
2336 | int i; | ||
2337 | int ok; | 2346 | int ok; |
2338 | 2347 | ||
2339 | l = dsi_read_reg(dsidev, DSI_DSIPHY_CFG5); | 2348 | l = dsi_read_reg(dsidev, DSI_DSIPHY_CFG5); |
2340 | 2349 | ||
2341 | ok = 0; | 2350 | ok = 0; |
2342 | for (i = 0; i < 3; ++i) { | 2351 | for (i = 0; i < dsi->num_lanes_supported; ++i) { |
2343 | if (!in_use[i] || (l & (1 << bits[i]))) | 2352 | if (!in_use[i] || (l & (1 << offsets[i]))) |
2344 | ok++; | 2353 | ok++; |
2345 | } | 2354 | } |
2346 | 2355 | ||
2347 | if (ok == 3) | 2356 | if (ok == dsi->num_lanes_supported) |
2348 | break; | 2357 | break; |
2349 | 2358 | ||
2350 | if (--t == 0) { | 2359 | if (--t == 0) { |
2351 | for (i = 0; i < 3; ++i) { | 2360 | for (i = 0; i < dsi->num_lanes_supported; ++i) { |
2352 | if (!in_use[i] || (l & (1 << bits[i]))) | 2361 | if (!in_use[i] || (l & (1 << offsets[i]))) |
2353 | continue; | 2362 | continue; |
2354 | 2363 | ||
2355 | DSSERR("CIO TXCLKESC%d domain not coming " \ | 2364 | DSSERR("CIO TXCLKESC%d domain not coming " \ |
@@ -2362,22 +2371,20 @@ static int dsi_cio_wait_tx_clk_esc_reset(struct omap_dss_device *dssdev) | |||
2362 | return 0; | 2371 | return 0; |
2363 | } | 2372 | } |
2364 | 2373 | ||
2374 | /* return bitmask of enabled lanes, lane0 being the lsb */ | ||
2365 | static unsigned dsi_get_lane_mask(struct omap_dss_device *dssdev) | 2375 | static unsigned dsi_get_lane_mask(struct omap_dss_device *dssdev) |
2366 | { | 2376 | { |
2367 | unsigned lanes = 0; | 2377 | struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); |
2378 | struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); | ||
2379 | unsigned mask = 0; | ||
2380 | int i; | ||
2368 | 2381 | ||
2369 | if (dssdev->phy.dsi.clk_lane != 0) | 2382 | for (i = 0; i < dsi->num_lanes_supported; ++i) { |
2370 | lanes |= 1 << (dssdev->phy.dsi.clk_lane - 1); | 2383 | if (dsi->lanes[i].function != DSI_LANE_UNUSED) |
2371 | if (dssdev->phy.dsi.data1_lane != 0) | 2384 | mask |= 1 << i; |
2372 | lanes |= 1 << (dssdev->phy.dsi.data1_lane - 1); | 2385 | } |
2373 | if (dssdev->phy.dsi.data2_lane != 0) | ||
2374 | lanes |= 1 << (dssdev->phy.dsi.data2_lane - 1); | ||
2375 | if (dssdev->phy.dsi.data3_lane != 0) | ||
2376 | lanes |= 1 << (dssdev->phy.dsi.data3_lane - 1); | ||
2377 | if (dssdev->phy.dsi.data4_lane != 0) | ||
2378 | lanes |= 1 << (dssdev->phy.dsi.data4_lane - 1); | ||
2379 | 2386 | ||
2380 | return lanes; | 2387 | return mask; |
2381 | } | 2388 | } |
2382 | 2389 | ||
2383 | static int dsi_cio_init(struct omap_dss_device *dssdev) | 2390 | static int dsi_cio_init(struct omap_dss_device *dssdev) |
@@ -2385,7 +2392,6 @@ static int dsi_cio_init(struct omap_dss_device *dssdev) | |||
2385 | struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); | 2392 | struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); |
2386 | struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); | 2393 | struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); |
2387 | int r; | 2394 | int r; |
2388 | int num_data_lanes_dssdev = dsi_get_num_data_lanes_dssdev(dssdev); | ||
2389 | u32 l; | 2395 | u32 l; |
2390 | 2396 | ||
2391 | DSSDBGF(); | 2397 | DSSDBGF(); |
@@ -2407,7 +2413,9 @@ static int dsi_cio_init(struct omap_dss_device *dssdev) | |||
2407 | goto err_scp_clk_dom; | 2413 | goto err_scp_clk_dom; |
2408 | } | 2414 | } |
2409 | 2415 | ||
2410 | dsi_set_lane_config(dssdev); | 2416 | r = dsi_set_lane_config(dssdev); |
2417 | if (r) | ||
2418 | goto err_scp_clk_dom; | ||
2411 | 2419 | ||
2412 | /* set TX STOP MODE timer to maximum for this operation */ | 2420 | /* set TX STOP MODE timer to maximum for this operation */ |
2413 | l = dsi_read_reg(dsidev, DSI_TIMING1); | 2421 | l = dsi_read_reg(dsidev, DSI_TIMING1); |
@@ -2418,7 +2426,8 @@ static int dsi_cio_init(struct omap_dss_device *dssdev) | |||
2418 | dsi_write_reg(dsidev, DSI_TIMING1, l); | 2426 | dsi_write_reg(dsidev, DSI_TIMING1, l); |
2419 | 2427 | ||
2420 | if (dsi->ulps_enabled) { | 2428 | if (dsi->ulps_enabled) { |
2421 | u32 lane_mask = DSI_CLK_P | DSI_DATA1_P | DSI_DATA2_P; | 2429 | unsigned mask_p; |
2430 | int i; | ||
2422 | 2431 | ||
2423 | DSSDBG("manual ulps exit\n"); | 2432 | DSSDBG("manual ulps exit\n"); |
2424 | 2433 | ||
@@ -2427,16 +2436,19 @@ static int dsi_cio_init(struct omap_dss_device *dssdev) | |||
2427 | * ULPS exit sequence, as after reset the DSS HW thinks | 2436 | * ULPS exit sequence, as after reset the DSS HW thinks |
2428 | * that we are not in ULPS mode, and refuses to send the | 2437 | * that we are not in ULPS mode, and refuses to send the |
2429 | * sequence. So we need to send the ULPS exit sequence | 2438 | * sequence. So we need to send the ULPS exit sequence |
2430 | * manually. | 2439 | * manually by setting positive lines high and negative lines |
2440 | * low for 1ms. | ||
2431 | */ | 2441 | */ |
2432 | 2442 | ||
2433 | if (num_data_lanes_dssdev > 2) | 2443 | mask_p = 0; |
2434 | lane_mask |= DSI_DATA3_P; | ||
2435 | 2444 | ||
2436 | if (num_data_lanes_dssdev > 3) | 2445 | for (i = 0; i < dsi->num_lanes_supported; ++i) { |
2437 | lane_mask |= DSI_DATA4_P; | 2446 | if (dsi->lanes[i].function == DSI_LANE_UNUSED) |
2447 | continue; | ||
2448 | mask_p |= 1 << i; | ||
2449 | } | ||
2438 | 2450 | ||
2439 | dsi_cio_enable_lane_override(dssdev, lane_mask); | 2451 | dsi_cio_enable_lane_override(dssdev, mask_p, 0); |
2440 | } | 2452 | } |
2441 | 2453 | ||
2442 | r = dsi_cio_power(dsidev, DSI_COMPLEXIO_POWER_ON); | 2454 | r = dsi_cio_power(dsidev, DSI_COMPLEXIO_POWER_ON); |
@@ -2913,6 +2925,9 @@ static int dsi_vc_send_bta(struct platform_device *dsidev, int channel) | |||
2913 | 2925 | ||
2914 | REG_FLD_MOD(dsidev, DSI_VC_CTRL(channel), 1, 6, 6); /* BTA_EN */ | 2926 | REG_FLD_MOD(dsidev, DSI_VC_CTRL(channel), 1, 6, 6); /* BTA_EN */ |
2915 | 2927 | ||
2928 | /* flush posted write */ | ||
2929 | dsi_read_reg(dsidev, DSI_VC_CTRL(channel)); | ||
2930 | |||
2916 | return 0; | 2931 | return 0; |
2917 | } | 2932 | } |
2918 | 2933 | ||
@@ -3513,7 +3528,8 @@ static int dsi_enter_ulps(struct platform_device *dsidev) | |||
3513 | { | 3528 | { |
3514 | struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); | 3529 | struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); |
3515 | DECLARE_COMPLETION_ONSTACK(completion); | 3530 | DECLARE_COMPLETION_ONSTACK(completion); |
3516 | int r; | 3531 | int r, i; |
3532 | unsigned mask; | ||
3517 | 3533 | ||
3518 | DSSDBGF(); | 3534 | DSSDBGF(); |
3519 | 3535 | ||
@@ -3524,9 +3540,11 @@ static int dsi_enter_ulps(struct platform_device *dsidev) | |||
3524 | if (dsi->ulps_enabled) | 3540 | if (dsi->ulps_enabled) |
3525 | return 0; | 3541 | return 0; |
3526 | 3542 | ||
3543 | /* DDR_CLK_ALWAYS_ON */ | ||
3527 | if (REG_GET(dsidev, DSI_CLK_CTRL, 13, 13)) { | 3544 | if (REG_GET(dsidev, DSI_CLK_CTRL, 13, 13)) { |
3528 | DSSERR("DDR_CLK_ALWAYS_ON enabled when entering ULPS\n"); | 3545 | dsi_if_enable(dsidev, 0); |
3529 | return -EIO; | 3546 | REG_FLD_MOD(dsidev, DSI_CLK_CTRL, 0, 13, 13); |
3547 | dsi_if_enable(dsidev, 1); | ||
3530 | } | 3548 | } |
3531 | 3549 | ||
3532 | dsi_sync_vc(dsidev, 0); | 3550 | dsi_sync_vc(dsidev, 0); |
@@ -3556,10 +3574,19 @@ static int dsi_enter_ulps(struct platform_device *dsidev) | |||
3556 | if (r) | 3574 | if (r) |
3557 | return r; | 3575 | return r; |
3558 | 3576 | ||
3577 | mask = 0; | ||
3578 | |||
3579 | for (i = 0; i < dsi->num_lanes_supported; ++i) { | ||
3580 | if (dsi->lanes[i].function == DSI_LANE_UNUSED) | ||
3581 | continue; | ||
3582 | mask |= 1 << i; | ||
3583 | } | ||
3559 | /* Assert TxRequestEsc for data lanes and TxUlpsClk for clk lane */ | 3584 | /* Assert TxRequestEsc for data lanes and TxUlpsClk for clk lane */ |
3560 | /* LANEx_ULPS_SIG2 */ | 3585 | /* LANEx_ULPS_SIG2 */ |
3561 | REG_FLD_MOD(dsidev, DSI_COMPLEXIO_CFG2, (1 << 0) | (1 << 1) | (1 << 2), | 3586 | REG_FLD_MOD(dsidev, DSI_COMPLEXIO_CFG2, mask, 9, 5); |
3562 | 7, 5); | 3587 | |
3588 | /* flush posted write and wait for SCP interface to finish the write */ | ||
3589 | dsi_read_reg(dsidev, DSI_COMPLEXIO_CFG2); | ||
3563 | 3590 | ||
3564 | if (wait_for_completion_timeout(&completion, | 3591 | if (wait_for_completion_timeout(&completion, |
3565 | msecs_to_jiffies(1000)) == 0) { | 3592 | msecs_to_jiffies(1000)) == 0) { |
@@ -3572,8 +3599,10 @@ static int dsi_enter_ulps(struct platform_device *dsidev) | |||
3572 | DSI_CIO_IRQ_ULPSACTIVENOT_ALL0); | 3599 | DSI_CIO_IRQ_ULPSACTIVENOT_ALL0); |
3573 | 3600 | ||
3574 | /* Reset LANEx_ULPS_SIG2 */ | 3601 | /* Reset LANEx_ULPS_SIG2 */ |
3575 | REG_FLD_MOD(dsidev, DSI_COMPLEXIO_CFG2, (0 << 0) | (0 << 1) | (0 << 2), | 3602 | REG_FLD_MOD(dsidev, DSI_COMPLEXIO_CFG2, 0, 9, 5); |
3576 | 7, 5); | 3603 | |
3604 | /* flush posted write and wait for SCP interface to finish the write */ | ||
3605 | dsi_read_reg(dsidev, DSI_COMPLEXIO_CFG2); | ||
3577 | 3606 | ||
3578 | dsi_cio_power(dsidev, DSI_COMPLEXIO_POWER_ULPS); | 3607 | dsi_cio_power(dsidev, DSI_COMPLEXIO_POWER_ULPS); |
3579 | 3608 | ||
@@ -3836,6 +3865,7 @@ static int dsi_proto_config(struct omap_dss_device *dssdev) | |||
3836 | static void dsi_proto_timings(struct omap_dss_device *dssdev) | 3865 | static void dsi_proto_timings(struct omap_dss_device *dssdev) |
3837 | { | 3866 | { |
3838 | struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); | 3867 | struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); |
3868 | struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); | ||
3839 | unsigned tlpx, tclk_zero, tclk_prepare, tclk_trail; | 3869 | unsigned tlpx, tclk_zero, tclk_prepare, tclk_trail; |
3840 | unsigned tclk_pre, tclk_post; | 3870 | unsigned tclk_pre, tclk_post; |
3841 | unsigned ths_prepare, ths_prepare_ths_zero, ths_zero; | 3871 | unsigned ths_prepare, ths_prepare_ths_zero, ths_zero; |
@@ -3843,7 +3873,7 @@ static void dsi_proto_timings(struct omap_dss_device *dssdev) | |||
3843 | unsigned ddr_clk_pre, ddr_clk_post; | 3873 | unsigned ddr_clk_pre, ddr_clk_post; |
3844 | unsigned enter_hs_mode_lat, exit_hs_mode_lat; | 3874 | unsigned enter_hs_mode_lat, exit_hs_mode_lat; |
3845 | unsigned ths_eot; | 3875 | unsigned ths_eot; |
3846 | int ndl = dsi_get_num_data_lanes_dssdev(dssdev); | 3876 | int ndl = dsi->num_lanes_used - 1; |
3847 | u32 r; | 3877 | u32 r; |
3848 | 3878 | ||
3849 | r = dsi_read_reg(dsidev, DSI_DSIPHY_CFG0); | 3879 | r = dsi_read_reg(dsidev, DSI_DSIPHY_CFG0); |
@@ -3945,68 +3975,82 @@ static void dsi_proto_timings(struct omap_dss_device *dssdev) | |||
3945 | } | 3975 | } |
3946 | } | 3976 | } |
3947 | 3977 | ||
3948 | int dsi_video_mode_enable(struct omap_dss_device *dssdev, int channel) | 3978 | int dsi_enable_video_output(struct omap_dss_device *dssdev, int channel) |
3949 | { | 3979 | { |
3950 | struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); | 3980 | struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); |
3951 | int bpp = dsi_get_pixel_size(dssdev->panel.dsi_pix_fmt); | 3981 | int bpp = dsi_get_pixel_size(dssdev->panel.dsi_pix_fmt); |
3952 | u8 data_type; | 3982 | u8 data_type; |
3953 | u16 word_count; | 3983 | u16 word_count; |
3984 | int r; | ||
3954 | 3985 | ||
3955 | switch (dssdev->panel.dsi_pix_fmt) { | 3986 | if (dssdev->panel.dsi_mode == OMAP_DSS_DSI_VIDEO_MODE) { |
3956 | case OMAP_DSS_DSI_FMT_RGB888: | 3987 | switch (dssdev->panel.dsi_pix_fmt) { |
3957 | data_type = MIPI_DSI_PACKED_PIXEL_STREAM_24; | 3988 | case OMAP_DSS_DSI_FMT_RGB888: |
3958 | break; | 3989 | data_type = MIPI_DSI_PACKED_PIXEL_STREAM_24; |
3959 | case OMAP_DSS_DSI_FMT_RGB666: | 3990 | break; |
3960 | data_type = MIPI_DSI_PIXEL_STREAM_3BYTE_18; | 3991 | case OMAP_DSS_DSI_FMT_RGB666: |
3961 | break; | 3992 | data_type = MIPI_DSI_PIXEL_STREAM_3BYTE_18; |
3962 | case OMAP_DSS_DSI_FMT_RGB666_PACKED: | 3993 | break; |
3963 | data_type = MIPI_DSI_PACKED_PIXEL_STREAM_18; | 3994 | case OMAP_DSS_DSI_FMT_RGB666_PACKED: |
3964 | break; | 3995 | data_type = MIPI_DSI_PACKED_PIXEL_STREAM_18; |
3965 | case OMAP_DSS_DSI_FMT_RGB565: | 3996 | break; |
3966 | data_type = MIPI_DSI_PACKED_PIXEL_STREAM_16; | 3997 | case OMAP_DSS_DSI_FMT_RGB565: |
3967 | break; | 3998 | data_type = MIPI_DSI_PACKED_PIXEL_STREAM_16; |
3968 | default: | 3999 | break; |
3969 | BUG(); | 4000 | default: |
3970 | }; | 4001 | BUG(); |
4002 | }; | ||
3971 | 4003 | ||
3972 | dsi_if_enable(dsidev, false); | 4004 | dsi_if_enable(dsidev, false); |
3973 | dsi_vc_enable(dsidev, channel, false); | 4005 | dsi_vc_enable(dsidev, channel, false); |
3974 | 4006 | ||
3975 | /* MODE, 1 = video mode */ | 4007 | /* MODE, 1 = video mode */ |
3976 | REG_FLD_MOD(dsidev, DSI_VC_CTRL(channel), 1, 4, 4); | 4008 | REG_FLD_MOD(dsidev, DSI_VC_CTRL(channel), 1, 4, 4); |
3977 | 4009 | ||
3978 | word_count = DIV_ROUND_UP(dssdev->panel.timings.x_res * bpp, 8); | 4010 | word_count = DIV_ROUND_UP(dssdev->panel.timings.x_res * bpp, 8); |
3979 | 4011 | ||
3980 | dsi_vc_write_long_header(dsidev, channel, data_type, word_count, 0); | 4012 | dsi_vc_write_long_header(dsidev, channel, data_type, |
4013 | word_count, 0); | ||
3981 | 4014 | ||
3982 | dsi_vc_enable(dsidev, channel, true); | 4015 | dsi_vc_enable(dsidev, channel, true); |
3983 | dsi_if_enable(dsidev, true); | 4016 | dsi_if_enable(dsidev, true); |
4017 | } | ||
3984 | 4018 | ||
3985 | dssdev->manager->enable(dssdev->manager); | 4019 | r = dss_mgr_enable(dssdev->manager); |
4020 | if (r) { | ||
4021 | if (dssdev->panel.dsi_mode == OMAP_DSS_DSI_VIDEO_MODE) { | ||
4022 | dsi_if_enable(dsidev, false); | ||
4023 | dsi_vc_enable(dsidev, channel, false); | ||
4024 | } | ||
4025 | |||
4026 | return r; | ||
4027 | } | ||
3986 | 4028 | ||
3987 | return 0; | 4029 | return 0; |
3988 | } | 4030 | } |
3989 | EXPORT_SYMBOL(dsi_video_mode_enable); | 4031 | EXPORT_SYMBOL(dsi_enable_video_output); |
3990 | 4032 | ||
3991 | void dsi_video_mode_disable(struct omap_dss_device *dssdev, int channel) | 4033 | void dsi_disable_video_output(struct omap_dss_device *dssdev, int channel) |
3992 | { | 4034 | { |
3993 | struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); | 4035 | struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); |
3994 | 4036 | ||
3995 | dsi_if_enable(dsidev, false); | 4037 | if (dssdev->panel.dsi_mode == OMAP_DSS_DSI_VIDEO_MODE) { |
3996 | dsi_vc_enable(dsidev, channel, false); | 4038 | dsi_if_enable(dsidev, false); |
4039 | dsi_vc_enable(dsidev, channel, false); | ||
3997 | 4040 | ||
3998 | /* MODE, 0 = command mode */ | 4041 | /* MODE, 0 = command mode */ |
3999 | REG_FLD_MOD(dsidev, DSI_VC_CTRL(channel), 0, 4, 4); | 4042 | REG_FLD_MOD(dsidev, DSI_VC_CTRL(channel), 0, 4, 4); |
4000 | 4043 | ||
4001 | dsi_vc_enable(dsidev, channel, true); | 4044 | dsi_vc_enable(dsidev, channel, true); |
4002 | dsi_if_enable(dsidev, true); | 4045 | dsi_if_enable(dsidev, true); |
4046 | } | ||
4003 | 4047 | ||
4004 | dssdev->manager->disable(dssdev->manager); | 4048 | dss_mgr_disable(dssdev->manager); |
4005 | } | 4049 | } |
4006 | EXPORT_SYMBOL(dsi_video_mode_disable); | 4050 | EXPORT_SYMBOL(dsi_disable_video_output); |
4007 | 4051 | ||
4008 | static void dsi_update_screen_dispc(struct omap_dss_device *dssdev, | 4052 | static void dsi_update_screen_dispc(struct omap_dss_device *dssdev, |
4009 | u16 x, u16 y, u16 w, u16 h) | 4053 | u16 w, u16 h) |
4010 | { | 4054 | { |
4011 | struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); | 4055 | struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); |
4012 | struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); | 4056 | struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); |
@@ -4021,8 +4065,7 @@ static void dsi_update_screen_dispc(struct omap_dss_device *dssdev, | |||
4021 | const unsigned channel = dsi->update_channel; | 4065 | const unsigned channel = dsi->update_channel; |
4022 | const unsigned line_buf_size = dsi_get_line_buf_size(dsidev); | 4066 | const unsigned line_buf_size = dsi_get_line_buf_size(dsidev); |
4023 | 4067 | ||
4024 | DSSDBG("dsi_update_screen_dispc(%d,%d %dx%d)\n", | 4068 | DSSDBG("dsi_update_screen_dispc(%dx%d)\n", w, h); |
4025 | x, y, w, h); | ||
4026 | 4069 | ||
4027 | dsi_vc_config_source(dsidev, channel, DSI_VC_SOURCE_VP); | 4070 | dsi_vc_config_source(dsidev, channel, DSI_VC_SOURCE_VP); |
4028 | 4071 | ||
@@ -4070,7 +4113,7 @@ static void dsi_update_screen_dispc(struct omap_dss_device *dssdev, | |||
4070 | msecs_to_jiffies(250)); | 4113 | msecs_to_jiffies(250)); |
4071 | BUG_ON(r == 0); | 4114 | BUG_ON(r == 0); |
4072 | 4115 | ||
4073 | dss_start_update(dssdev); | 4116 | dss_mgr_start_update(dssdev->manager); |
4074 | 4117 | ||
4075 | if (dsi->te_enabled) { | 4118 | if (dsi->te_enabled) { |
4076 | /* disable LP_RX_TO, so that we can receive TE. Time to wait | 4119 | /* disable LP_RX_TO, so that we can receive TE. Time to wait |
@@ -4146,66 +4189,27 @@ static void dsi_framedone_irq_callback(void *data, u32 mask) | |||
4146 | #endif | 4189 | #endif |
4147 | } | 4190 | } |
4148 | 4191 | ||
4149 | int omap_dsi_prepare_update(struct omap_dss_device *dssdev, | 4192 | int omap_dsi_update(struct omap_dss_device *dssdev, int channel, |
4150 | u16 *x, u16 *y, u16 *w, u16 *h, | 4193 | void (*callback)(int, void *), void *data) |
4151 | bool enlarge_update_area) | ||
4152 | { | 4194 | { |
4153 | struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); | 4195 | struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); |
4196 | struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); | ||
4154 | u16 dw, dh; | 4197 | u16 dw, dh; |
4155 | 4198 | ||
4156 | dssdev->driver->get_resolution(dssdev, &dw, &dh); | ||
4157 | |||
4158 | if (*x > dw || *y > dh) | ||
4159 | return -EINVAL; | ||
4160 | |||
4161 | if (*x + *w > dw) | ||
4162 | return -EINVAL; | ||
4163 | |||
4164 | if (*y + *h > dh) | ||
4165 | return -EINVAL; | ||
4166 | |||
4167 | if (*w == 1) | ||
4168 | return -EINVAL; | ||
4169 | |||
4170 | if (*w == 0 || *h == 0) | ||
4171 | return -EINVAL; | ||
4172 | |||
4173 | dsi_perf_mark_setup(dsidev); | 4199 | dsi_perf_mark_setup(dsidev); |
4174 | 4200 | ||
4175 | dss_setup_partial_planes(dssdev, x, y, w, h, | ||
4176 | enlarge_update_area); | ||
4177 | dispc_mgr_set_lcd_size(dssdev->manager->id, *w, *h); | ||
4178 | |||
4179 | return 0; | ||
4180 | } | ||
4181 | EXPORT_SYMBOL(omap_dsi_prepare_update); | ||
4182 | |||
4183 | int omap_dsi_update(struct omap_dss_device *dssdev, | ||
4184 | int channel, | ||
4185 | u16 x, u16 y, u16 w, u16 h, | ||
4186 | void (*callback)(int, void *), void *data) | ||
4187 | { | ||
4188 | struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); | ||
4189 | struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); | ||
4190 | |||
4191 | dsi->update_channel = channel; | 4201 | dsi->update_channel = channel; |
4192 | 4202 | ||
4193 | /* OMAP DSS cannot send updates of odd widths. | ||
4194 | * omap_dsi_prepare_update() makes the widths even, but add a BUG_ON | ||
4195 | * here to make sure we catch erroneous updates. Otherwise we'll only | ||
4196 | * see rather obscure HW error happening, as DSS halts. */ | ||
4197 | BUG_ON(x % 2 == 1); | ||
4198 | |||
4199 | dsi->framedone_callback = callback; | 4203 | dsi->framedone_callback = callback; |
4200 | dsi->framedone_data = data; | 4204 | dsi->framedone_data = data; |
4201 | 4205 | ||
4202 | dsi->update_region.x = x; | 4206 | dssdev->driver->get_resolution(dssdev, &dw, &dh); |
4203 | dsi->update_region.y = y; | ||
4204 | dsi->update_region.w = w; | ||
4205 | dsi->update_region.h = h; | ||
4206 | dsi->update_region.device = dssdev; | ||
4207 | 4207 | ||
4208 | dsi_update_screen_dispc(dssdev, x, y, w, h); | 4208 | #ifdef DEBUG |
4209 | dsi->update_bytes = dw * dh * | ||
4210 | dsi_get_pixel_size(dssdev->panel.dsi_pix_fmt) / 8; | ||
4211 | #endif | ||
4212 | dsi_update_screen_dispc(dssdev, dw, dh); | ||
4209 | 4213 | ||
4210 | return 0; | 4214 | return 0; |
4211 | } | 4215 | } |
@@ -4218,6 +4222,7 @@ static int dsi_display_init_dispc(struct omap_dss_device *dssdev) | |||
4218 | int r; | 4222 | int r; |
4219 | 4223 | ||
4220 | if (dssdev->panel.dsi_mode == OMAP_DSS_DSI_CMD_MODE) { | 4224 | if (dssdev->panel.dsi_mode == OMAP_DSS_DSI_CMD_MODE) { |
4225 | u16 dw, dh; | ||
4221 | u32 irq; | 4226 | u32 irq; |
4222 | struct omap_video_timings timings = { | 4227 | struct omap_video_timings timings = { |
4223 | .hsw = 1, | 4228 | .hsw = 1, |
@@ -4228,6 +4233,10 @@ static int dsi_display_init_dispc(struct omap_dss_device *dssdev) | |||
4228 | .vbp = 0, | 4233 | .vbp = 0, |
4229 | }; | 4234 | }; |
4230 | 4235 | ||
4236 | dssdev->driver->get_resolution(dssdev, &dw, &dh); | ||
4237 | timings.x_res = dw; | ||
4238 | timings.y_res = dh; | ||
4239 | |||
4231 | irq = dssdev->manager->id == OMAP_DSS_CHANNEL_LCD ? | 4240 | irq = dssdev->manager->id == OMAP_DSS_CHANNEL_LCD ? |
4232 | DISPC_IRQ_FRAMEDONE : DISPC_IRQ_FRAMEDONE2; | 4241 | DISPC_IRQ_FRAMEDONE : DISPC_IRQ_FRAMEDONE2; |
4233 | 4242 | ||
@@ -4330,6 +4339,12 @@ static int dsi_display_init_dsi(struct omap_dss_device *dssdev) | |||
4330 | int dsi_module = dsi_get_dsidev_id(dsidev); | 4339 | int dsi_module = dsi_get_dsidev_id(dsidev); |
4331 | int r; | 4340 | int r; |
4332 | 4341 | ||
4342 | r = dsi_parse_lane_config(dssdev); | ||
4343 | if (r) { | ||
4344 | DSSERR("illegal lane config"); | ||
4345 | goto err0; | ||
4346 | } | ||
4347 | |||
4333 | r = dsi_pll_init(dsidev, true, true); | 4348 | r = dsi_pll_init(dsidev, true, true); |
4334 | if (r) | 4349 | if (r) |
4335 | goto err0; | 4350 | goto err0; |
@@ -4521,7 +4536,6 @@ int dsi_init_display(struct omap_dss_device *dssdev) | |||
4521 | { | 4536 | { |
4522 | struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); | 4537 | struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); |
4523 | struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); | 4538 | struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); |
4524 | int dsi_module = dsi_get_dsidev_id(dsidev); | ||
4525 | 4539 | ||
4526 | DSSDBG("DSI init\n"); | 4540 | DSSDBG("DSI init\n"); |
4527 | 4541 | ||
@@ -4543,12 +4557,6 @@ int dsi_init_display(struct omap_dss_device *dssdev) | |||
4543 | dsi->vdds_dsi_reg = vdds_dsi; | 4557 | dsi->vdds_dsi_reg = vdds_dsi; |
4544 | } | 4558 | } |
4545 | 4559 | ||
4546 | if (dsi_get_num_data_lanes_dssdev(dssdev) > dsi->num_data_lanes) { | ||
4547 | DSSERR("DSI%d can't support more than %d data lanes\n", | ||
4548 | dsi_module + 1, dsi->num_data_lanes); | ||
4549 | return -EINVAL; | ||
4550 | } | ||
4551 | |||
4552 | return 0; | 4560 | return 0; |
4553 | } | 4561 | } |
4554 | 4562 | ||
@@ -4771,7 +4779,13 @@ static int omap_dsihw_probe(struct platform_device *dsidev) | |||
4771 | dev_dbg(&dsidev->dev, "OMAP DSI rev %d.%d\n", | 4779 | dev_dbg(&dsidev->dev, "OMAP DSI rev %d.%d\n", |
4772 | FLD_GET(rev, 7, 4), FLD_GET(rev, 3, 0)); | 4780 | FLD_GET(rev, 7, 4), FLD_GET(rev, 3, 0)); |
4773 | 4781 | ||
4774 | dsi->num_data_lanes = dsi_get_num_data_lanes(dsidev); | 4782 | /* DSI on OMAP3 doesn't have register DSI_GNQ, set number |
4783 | * of data to 3 by default */ | ||
4784 | if (dss_has_feature(FEAT_DSI_GNQ)) | ||
4785 | /* NB_DATA_LANES */ | ||
4786 | dsi->num_lanes_supported = 1 + REG_GET(dsidev, DSI_GNQ, 11, 9); | ||
4787 | else | ||
4788 | dsi->num_lanes_supported = 3; | ||
4775 | 4789 | ||
4776 | dsi_runtime_put(dsidev); | 4790 | dsi_runtime_put(dsidev); |
4777 | 4791 | ||
diff --git a/drivers/video/omap2/dss/dss.h b/drivers/video/omap2/dss/dss.h index 57a52eecee91..32ff69fb3333 100644 --- a/drivers/video/omap2/dss/dss.h +++ b/drivers/video/omap2/dss/dss.h | |||
@@ -163,6 +163,34 @@ struct bus_type *dss_get_bus(void); | |||
163 | struct regulator *dss_get_vdds_dsi(void); | 163 | struct regulator *dss_get_vdds_dsi(void); |
164 | struct regulator *dss_get_vdds_sdi(void); | 164 | struct regulator *dss_get_vdds_sdi(void); |
165 | 165 | ||
166 | /* apply */ | ||
167 | void dss_apply_init(void); | ||
168 | int dss_mgr_wait_for_go(struct omap_overlay_manager *mgr); | ||
169 | int dss_mgr_wait_for_go_ovl(struct omap_overlay *ovl); | ||
170 | void dss_mgr_start_update(struct omap_overlay_manager *mgr); | ||
171 | int omap_dss_mgr_apply(struct omap_overlay_manager *mgr); | ||
172 | |||
173 | int dss_mgr_enable(struct omap_overlay_manager *mgr); | ||
174 | void dss_mgr_disable(struct omap_overlay_manager *mgr); | ||
175 | int dss_mgr_set_info(struct omap_overlay_manager *mgr, | ||
176 | struct omap_overlay_manager_info *info); | ||
177 | void dss_mgr_get_info(struct omap_overlay_manager *mgr, | ||
178 | struct omap_overlay_manager_info *info); | ||
179 | int dss_mgr_set_device(struct omap_overlay_manager *mgr, | ||
180 | struct omap_dss_device *dssdev); | ||
181 | int dss_mgr_unset_device(struct omap_overlay_manager *mgr); | ||
182 | |||
183 | bool dss_ovl_is_enabled(struct omap_overlay *ovl); | ||
184 | int dss_ovl_enable(struct omap_overlay *ovl); | ||
185 | int dss_ovl_disable(struct omap_overlay *ovl); | ||
186 | int dss_ovl_set_info(struct omap_overlay *ovl, | ||
187 | struct omap_overlay_info *info); | ||
188 | void dss_ovl_get_info(struct omap_overlay *ovl, | ||
189 | struct omap_overlay_info *info); | ||
190 | int dss_ovl_set_manager(struct omap_overlay *ovl, | ||
191 | struct omap_overlay_manager *mgr); | ||
192 | int dss_ovl_unset_manager(struct omap_overlay *ovl); | ||
193 | |||
166 | /* display */ | 194 | /* display */ |
167 | int dss_suspend_all_devices(void); | 195 | int dss_suspend_all_devices(void); |
168 | int dss_resume_all_devices(void); | 196 | int dss_resume_all_devices(void); |
@@ -181,21 +209,22 @@ void default_get_overlay_fifo_thresholds(enum omap_plane plane, | |||
181 | /* manager */ | 209 | /* manager */ |
182 | int dss_init_overlay_managers(struct platform_device *pdev); | 210 | int dss_init_overlay_managers(struct platform_device *pdev); |
183 | void dss_uninit_overlay_managers(struct platform_device *pdev); | 211 | void dss_uninit_overlay_managers(struct platform_device *pdev); |
184 | int dss_mgr_wait_for_go_ovl(struct omap_overlay *ovl); | 212 | int dss_mgr_simple_check(struct omap_overlay_manager *mgr, |
185 | void dss_setup_partial_planes(struct omap_dss_device *dssdev, | 213 | const struct omap_overlay_manager_info *info); |
186 | u16 *x, u16 *y, u16 *w, u16 *h, | 214 | int dss_mgr_check(struct omap_overlay_manager *mgr, |
187 | bool enlarge_update_area); | 215 | struct omap_dss_device *dssdev, |
188 | void dss_start_update(struct omap_dss_device *dssdev); | 216 | struct omap_overlay_manager_info *info, |
217 | struct omap_overlay_info **overlay_infos); | ||
189 | 218 | ||
190 | /* overlay */ | 219 | /* overlay */ |
191 | void dss_init_overlays(struct platform_device *pdev); | 220 | void dss_init_overlays(struct platform_device *pdev); |
192 | void dss_uninit_overlays(struct platform_device *pdev); | 221 | void dss_uninit_overlays(struct platform_device *pdev); |
193 | int dss_check_overlay(struct omap_overlay *ovl, struct omap_dss_device *dssdev); | ||
194 | void dss_overlay_setup_dispc_manager(struct omap_overlay_manager *mgr); | 222 | void dss_overlay_setup_dispc_manager(struct omap_overlay_manager *mgr); |
195 | #ifdef L4_EXAMPLE | ||
196 | void dss_overlay_setup_l4_manager(struct omap_overlay_manager *mgr); | ||
197 | #endif | ||
198 | void dss_recheck_connections(struct omap_dss_device *dssdev, bool force); | 223 | void dss_recheck_connections(struct omap_dss_device *dssdev, bool force); |
224 | int dss_ovl_simple_check(struct omap_overlay *ovl, | ||
225 | const struct omap_overlay_info *info); | ||
226 | int dss_ovl_check(struct omap_overlay *ovl, | ||
227 | struct omap_overlay_info *info, struct omap_dss_device *dssdev); | ||
199 | 228 | ||
200 | /* DSS */ | 229 | /* DSS */ |
201 | int dss_init_platform_driver(void); | 230 | int dss_init_platform_driver(void); |
@@ -399,21 +428,22 @@ int dispc_calc_clock_rates(unsigned long dispc_fclk_rate, | |||
399 | struct dispc_clock_info *cinfo); | 428 | struct dispc_clock_info *cinfo); |
400 | 429 | ||
401 | 430 | ||
431 | void dispc_ovl_set_fifo_threshold(enum omap_plane plane, u32 low, u32 high); | ||
402 | u32 dispc_ovl_get_fifo_size(enum omap_plane plane); | 432 | u32 dispc_ovl_get_fifo_size(enum omap_plane plane); |
403 | u32 dispc_ovl_get_burst_size(enum omap_plane plane); | 433 | u32 dispc_ovl_get_burst_size(enum omap_plane plane); |
404 | int dispc_ovl_setup(enum omap_plane plane, struct omap_overlay_info *oi, | 434 | int dispc_ovl_setup(enum omap_plane plane, struct omap_overlay_info *oi, |
405 | bool ilace, enum omap_channel channel, bool replication, | 435 | bool ilace, bool replication); |
406 | u32 fifo_low, u32 fifo_high); | ||
407 | int dispc_ovl_enable(enum omap_plane plane, bool enable); | 436 | int dispc_ovl_enable(enum omap_plane plane, bool enable); |
408 | 437 | void dispc_ovl_set_channel_out(enum omap_plane plane, | |
438 | enum omap_channel channel); | ||
409 | 439 | ||
410 | void dispc_mgr_enable_fifohandcheck(enum omap_channel channel, bool enable); | 440 | void dispc_mgr_enable_fifohandcheck(enum omap_channel channel, bool enable); |
411 | void dispc_mgr_set_lcd_size(enum omap_channel channel, u16 width, u16 height); | 441 | void dispc_mgr_set_lcd_size(enum omap_channel channel, u16 width, u16 height); |
412 | void dispc_mgr_enable_cpr(enum omap_channel channel, bool enable); | 442 | u32 dispc_mgr_get_vsync_irq(enum omap_channel channel); |
413 | void dispc_mgr_set_cpr_coef(enum omap_channel channel, | 443 | u32 dispc_mgr_get_framedone_irq(enum omap_channel channel); |
414 | struct omap_dss_cpr_coefs *coefs); | ||
415 | bool dispc_mgr_go_busy(enum omap_channel channel); | 444 | bool dispc_mgr_go_busy(enum omap_channel channel); |
416 | void dispc_mgr_go(enum omap_channel channel); | 445 | void dispc_mgr_go(enum omap_channel channel); |
446 | bool dispc_mgr_is_enabled(enum omap_channel channel); | ||
417 | void dispc_mgr_enable(enum omap_channel channel, bool enable); | 447 | void dispc_mgr_enable(enum omap_channel channel, bool enable); |
418 | bool dispc_mgr_is_channel_enabled(enum omap_channel channel); | 448 | bool dispc_mgr_is_channel_enabled(enum omap_channel channel); |
419 | void dispc_mgr_set_io_pad_mode(enum dss_io_pad_mode mode); | 449 | void dispc_mgr_set_io_pad_mode(enum dss_io_pad_mode mode); |
@@ -421,18 +451,6 @@ void dispc_mgr_enable_stallmode(enum omap_channel channel, bool enable); | |||
421 | void dispc_mgr_set_tft_data_lines(enum omap_channel channel, u8 data_lines); | 451 | void dispc_mgr_set_tft_data_lines(enum omap_channel channel, u8 data_lines); |
422 | void dispc_mgr_set_lcd_display_type(enum omap_channel channel, | 452 | void dispc_mgr_set_lcd_display_type(enum omap_channel channel, |
423 | enum omap_lcd_display_type type); | 453 | enum omap_lcd_display_type type); |
424 | void dispc_mgr_set_default_color(enum omap_channel channel, u32 color); | ||
425 | u32 dispc_mgr_get_default_color(enum omap_channel channel); | ||
426 | void dispc_mgr_set_trans_key(enum omap_channel ch, | ||
427 | enum omap_dss_trans_key_type type, | ||
428 | u32 trans_key); | ||
429 | void dispc_mgr_get_trans_key(enum omap_channel ch, | ||
430 | enum omap_dss_trans_key_type *type, | ||
431 | u32 *trans_key); | ||
432 | void dispc_mgr_enable_trans_key(enum omap_channel ch, bool enable); | ||
433 | void dispc_mgr_enable_alpha_fixed_zorder(enum omap_channel ch, bool enable); | ||
434 | bool dispc_mgr_trans_key_enabled(enum omap_channel ch); | ||
435 | bool dispc_mgr_alpha_fixed_zorder_enabled(enum omap_channel ch); | ||
436 | void dispc_mgr_set_lcd_timings(enum omap_channel channel, | 454 | void dispc_mgr_set_lcd_timings(enum omap_channel channel, |
437 | struct omap_video_timings *timings); | 455 | struct omap_video_timings *timings); |
438 | void dispc_mgr_set_pol_freq(enum omap_channel channel, | 456 | void dispc_mgr_set_pol_freq(enum omap_channel channel, |
@@ -443,6 +461,8 @@ int dispc_mgr_set_clock_div(enum omap_channel channel, | |||
443 | struct dispc_clock_info *cinfo); | 461 | struct dispc_clock_info *cinfo); |
444 | int dispc_mgr_get_clock_div(enum omap_channel channel, | 462 | int dispc_mgr_get_clock_div(enum omap_channel channel, |
445 | struct dispc_clock_info *cinfo); | 463 | struct dispc_clock_info *cinfo); |
464 | void dispc_mgr_setup(enum omap_channel channel, | ||
465 | struct omap_overlay_manager_info *info); | ||
446 | 466 | ||
447 | /* VENC */ | 467 | /* VENC */ |
448 | #ifdef CONFIG_OMAP2_DSS_VENC | 468 | #ifdef CONFIG_OMAP2_DSS_VENC |
diff --git a/drivers/video/omap2/dss/dss_features.c b/drivers/video/omap2/dss/dss_features.c index b402699168a5..afcb59301c37 100644 --- a/drivers/video/omap2/dss/dss_features.c +++ b/drivers/video/omap2/dss/dss_features.c | |||
@@ -304,6 +304,11 @@ static const struct dss_param_range omap2_dss_param_range[] = { | |||
304 | [FEAT_PARAM_DSIPLL_FINT] = { 0, 0 }, | 304 | [FEAT_PARAM_DSIPLL_FINT] = { 0, 0 }, |
305 | [FEAT_PARAM_DSIPLL_LPDIV] = { 0, 0 }, | 305 | [FEAT_PARAM_DSIPLL_LPDIV] = { 0, 0 }, |
306 | [FEAT_PARAM_DOWNSCALE] = { 1, 2 }, | 306 | [FEAT_PARAM_DOWNSCALE] = { 1, 2 }, |
307 | /* | ||
308 | * Assuming the line width buffer to be 768 pixels as OMAP2 DISPC | ||
309 | * scaler cannot scale a image with width more than 768. | ||
310 | */ | ||
311 | [FEAT_PARAM_LINEWIDTH] = { 1, 768 }, | ||
307 | }; | 312 | }; |
308 | 313 | ||
309 | static const struct dss_param_range omap3_dss_param_range[] = { | 314 | static const struct dss_param_range omap3_dss_param_range[] = { |
@@ -316,6 +321,7 @@ static const struct dss_param_range omap3_dss_param_range[] = { | |||
316 | [FEAT_PARAM_DSIPLL_FINT] = { 750000, 2100000 }, | 321 | [FEAT_PARAM_DSIPLL_FINT] = { 750000, 2100000 }, |
317 | [FEAT_PARAM_DSIPLL_LPDIV] = { 1, (1 << 13) - 1}, | 322 | [FEAT_PARAM_DSIPLL_LPDIV] = { 1, (1 << 13) - 1}, |
318 | [FEAT_PARAM_DOWNSCALE] = { 1, 4 }, | 323 | [FEAT_PARAM_DOWNSCALE] = { 1, 4 }, |
324 | [FEAT_PARAM_LINEWIDTH] = { 1, 1024 }, | ||
319 | }; | 325 | }; |
320 | 326 | ||
321 | static const struct dss_param_range omap4_dss_param_range[] = { | 327 | static const struct dss_param_range omap4_dss_param_range[] = { |
@@ -328,6 +334,7 @@ static const struct dss_param_range omap4_dss_param_range[] = { | |||
328 | [FEAT_PARAM_DSIPLL_FINT] = { 500000, 2500000 }, | 334 | [FEAT_PARAM_DSIPLL_FINT] = { 500000, 2500000 }, |
329 | [FEAT_PARAM_DSIPLL_LPDIV] = { 0, (1 << 13) - 1 }, | 335 | [FEAT_PARAM_DSIPLL_LPDIV] = { 0, (1 << 13) - 1 }, |
330 | [FEAT_PARAM_DOWNSCALE] = { 1, 4 }, | 336 | [FEAT_PARAM_DOWNSCALE] = { 1, 4 }, |
337 | [FEAT_PARAM_LINEWIDTH] = { 1, 2048 }, | ||
331 | }; | 338 | }; |
332 | 339 | ||
333 | /* OMAP2 DSS Features */ | 340 | /* OMAP2 DSS Features */ |
@@ -465,6 +472,10 @@ static const struct ti_hdmi_ip_ops omap4_hdmi_functions = { | |||
465 | .dump_core = ti_hdmi_4xxx_core_dump, | 472 | .dump_core = ti_hdmi_4xxx_core_dump, |
466 | .dump_pll = ti_hdmi_4xxx_pll_dump, | 473 | .dump_pll = ti_hdmi_4xxx_pll_dump, |
467 | .dump_phy = ti_hdmi_4xxx_phy_dump, | 474 | .dump_phy = ti_hdmi_4xxx_phy_dump, |
475 | #if defined(CONFIG_SND_OMAP_SOC_OMAP4_HDMI) || \ | ||
476 | defined(CONFIG_SND_OMAP_SOC_OMAP4_HDMI_MODULE) | ||
477 | .audio_enable = ti_hdmi_4xxx_wp_audio_enable, | ||
478 | #endif | ||
468 | 479 | ||
469 | }; | 480 | }; |
470 | 481 | ||
diff --git a/drivers/video/omap2/dss/dss_features.h b/drivers/video/omap2/dss/dss_features.h index 6a6c05dd45ce..cd833bbaac3d 100644 --- a/drivers/video/omap2/dss/dss_features.h +++ b/drivers/video/omap2/dss/dss_features.h | |||
@@ -86,6 +86,7 @@ enum dss_range_param { | |||
86 | FEAT_PARAM_DSIPLL_FINT, | 86 | FEAT_PARAM_DSIPLL_FINT, |
87 | FEAT_PARAM_DSIPLL_LPDIV, | 87 | FEAT_PARAM_DSIPLL_LPDIV, |
88 | FEAT_PARAM_DOWNSCALE, | 88 | FEAT_PARAM_DOWNSCALE, |
89 | FEAT_PARAM_LINEWIDTH, | ||
89 | }; | 90 | }; |
90 | 91 | ||
91 | /* DSS Feature Functions */ | 92 | /* DSS Feature Functions */ |
diff --git a/drivers/video/omap2/dss/hdmi.c b/drivers/video/omap2/dss/hdmi.c index c56378c555b0..b4c270edb915 100644 --- a/drivers/video/omap2/dss/hdmi.c +++ b/drivers/video/omap2/dss/hdmi.c | |||
@@ -333,7 +333,7 @@ static int hdmi_power_on(struct omap_dss_device *dssdev) | |||
333 | if (r) | 333 | if (r) |
334 | return r; | 334 | return r; |
335 | 335 | ||
336 | dispc_mgr_enable(OMAP_DSS_CHANNEL_DIGIT, 0); | 336 | dss_mgr_disable(dssdev->manager); |
337 | 337 | ||
338 | p = &dssdev->panel.timings; | 338 | p = &dssdev->panel.timings; |
339 | 339 | ||
@@ -387,9 +387,16 @@ static int hdmi_power_on(struct omap_dss_device *dssdev) | |||
387 | 387 | ||
388 | hdmi.ip_data.ops->video_enable(&hdmi.ip_data, 1); | 388 | hdmi.ip_data.ops->video_enable(&hdmi.ip_data, 1); |
389 | 389 | ||
390 | dispc_mgr_enable(OMAP_DSS_CHANNEL_DIGIT, 1); | 390 | r = dss_mgr_enable(dssdev->manager); |
391 | if (r) | ||
392 | goto err_mgr_enable; | ||
391 | 393 | ||
392 | return 0; | 394 | return 0; |
395 | |||
396 | err_mgr_enable: | ||
397 | hdmi.ip_data.ops->video_enable(&hdmi.ip_data, 0); | ||
398 | hdmi.ip_data.ops->phy_disable(&hdmi.ip_data); | ||
399 | hdmi.ip_data.ops->pll_disable(&hdmi.ip_data); | ||
393 | err: | 400 | err: |
394 | hdmi_runtime_put(); | 401 | hdmi_runtime_put(); |
395 | return -EIO; | 402 | return -EIO; |
@@ -397,7 +404,7 @@ err: | |||
397 | 404 | ||
398 | static void hdmi_power_off(struct omap_dss_device *dssdev) | 405 | static void hdmi_power_off(struct omap_dss_device *dssdev) |
399 | { | 406 | { |
400 | dispc_mgr_enable(OMAP_DSS_CHANNEL_DIGIT, 0); | 407 | dss_mgr_disable(dssdev->manager); |
401 | 408 | ||
402 | hdmi.ip_data.ops->video_enable(&hdmi.ip_data, 0); | 409 | hdmi.ip_data.ops->video_enable(&hdmi.ip_data, 0); |
403 | hdmi.ip_data.ops->phy_disable(&hdmi.ip_data); | 410 | hdmi.ip_data.ops->phy_disable(&hdmi.ip_data); |
@@ -554,11 +561,44 @@ void omapdss_hdmi_display_disable(struct omap_dss_device *dssdev) | |||
554 | #if defined(CONFIG_SND_OMAP_SOC_OMAP4_HDMI) || \ | 561 | #if defined(CONFIG_SND_OMAP_SOC_OMAP4_HDMI) || \ |
555 | defined(CONFIG_SND_OMAP_SOC_OMAP4_HDMI_MODULE) | 562 | defined(CONFIG_SND_OMAP_SOC_OMAP4_HDMI_MODULE) |
556 | 563 | ||
557 | static int hdmi_audio_hw_params(struct hdmi_ip_data *ip_data, | 564 | static int hdmi_audio_trigger(struct snd_pcm_substream *substream, int cmd, |
558 | struct snd_pcm_substream *substream, | 565 | struct snd_soc_dai *dai) |
566 | { | ||
567 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
568 | struct snd_soc_codec *codec = rtd->codec; | ||
569 | struct platform_device *pdev = to_platform_device(codec->dev); | ||
570 | struct hdmi_ip_data *ip_data = snd_soc_codec_get_drvdata(codec); | ||
571 | int err = 0; | ||
572 | |||
573 | if (!(ip_data->ops) && !(ip_data->ops->audio_enable)) { | ||
574 | dev_err(&pdev->dev, "Cannot enable/disable audio\n"); | ||
575 | return -ENODEV; | ||
576 | } | ||
577 | |||
578 | switch (cmd) { | ||
579 | case SNDRV_PCM_TRIGGER_START: | ||
580 | case SNDRV_PCM_TRIGGER_RESUME: | ||
581 | case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: | ||
582 | ip_data->ops->audio_enable(ip_data, true); | ||
583 | break; | ||
584 | case SNDRV_PCM_TRIGGER_STOP: | ||
585 | case SNDRV_PCM_TRIGGER_SUSPEND: | ||
586 | case SNDRV_PCM_TRIGGER_PAUSE_PUSH: | ||
587 | ip_data->ops->audio_enable(ip_data, false); | ||
588 | break; | ||
589 | default: | ||
590 | err = -EINVAL; | ||
591 | } | ||
592 | return err; | ||
593 | } | ||
594 | |||
595 | static int hdmi_audio_hw_params(struct snd_pcm_substream *substream, | ||
559 | struct snd_pcm_hw_params *params, | 596 | struct snd_pcm_hw_params *params, |
560 | struct snd_soc_dai *dai) | 597 | struct snd_soc_dai *dai) |
561 | { | 598 | { |
599 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
600 | struct snd_soc_codec *codec = rtd->codec; | ||
601 | struct hdmi_ip_data *ip_data = snd_soc_codec_get_drvdata(codec); | ||
562 | struct hdmi_audio_format audio_format; | 602 | struct hdmi_audio_format audio_format; |
563 | struct hdmi_audio_dma audio_dma; | 603 | struct hdmi_audio_dma audio_dma; |
564 | struct hdmi_core_audio_config core_cfg; | 604 | struct hdmi_core_audio_config core_cfg; |
@@ -698,7 +738,16 @@ static int hdmi_audio_startup(struct snd_pcm_substream *substream, | |||
698 | return 0; | 738 | return 0; |
699 | } | 739 | } |
700 | 740 | ||
741 | static int hdmi_audio_codec_probe(struct snd_soc_codec *codec) | ||
742 | { | ||
743 | struct hdmi_ip_data *priv = &hdmi.ip_data; | ||
744 | |||
745 | snd_soc_codec_set_drvdata(codec, priv); | ||
746 | return 0; | ||
747 | } | ||
748 | |||
701 | static struct snd_soc_codec_driver hdmi_audio_codec_drv = { | 749 | static struct snd_soc_codec_driver hdmi_audio_codec_drv = { |
750 | .probe = hdmi_audio_codec_probe, | ||
702 | }; | 751 | }; |
703 | 752 | ||
704 | static struct snd_soc_dai_ops hdmi_audio_codec_ops = { | 753 | static struct snd_soc_dai_ops hdmi_audio_codec_ops = { |
diff --git a/drivers/video/omap2/dss/manager.c b/drivers/video/omap2/dss/manager.c index 6e63845cc7d7..d1858e71c64e 100644 --- a/drivers/video/omap2/dss/manager.c +++ b/drivers/video/omap2/dss/manager.c | |||
@@ -26,17 +26,15 @@ | |||
26 | #include <linux/slab.h> | 26 | #include <linux/slab.h> |
27 | #include <linux/module.h> | 27 | #include <linux/module.h> |
28 | #include <linux/platform_device.h> | 28 | #include <linux/platform_device.h> |
29 | #include <linux/spinlock.h> | ||
30 | #include <linux/jiffies.h> | 29 | #include <linux/jiffies.h> |
31 | 30 | ||
32 | #include <video/omapdss.h> | 31 | #include <video/omapdss.h> |
33 | #include <plat/cpu.h> | ||
34 | 32 | ||
35 | #include "dss.h" | 33 | #include "dss.h" |
36 | #include "dss_features.h" | 34 | #include "dss_features.h" |
37 | 35 | ||
38 | static int num_managers; | 36 | static int num_managers; |
39 | static struct list_head manager_list; | 37 | static struct omap_overlay_manager *managers; |
40 | 38 | ||
41 | static ssize_t manager_name_show(struct omap_overlay_manager *mgr, char *buf) | 39 | static ssize_t manager_name_show(struct omap_overlay_manager *mgr, char *buf) |
42 | { | 40 | { |
@@ -106,7 +104,11 @@ put_device: | |||
106 | static ssize_t manager_default_color_show(struct omap_overlay_manager *mgr, | 104 | static ssize_t manager_default_color_show(struct omap_overlay_manager *mgr, |
107 | char *buf) | 105 | char *buf) |
108 | { | 106 | { |
109 | return snprintf(buf, PAGE_SIZE, "%#x\n", mgr->info.default_color); | 107 | struct omap_overlay_manager_info info; |
108 | |||
109 | mgr->get_manager_info(mgr, &info); | ||
110 | |||
111 | return snprintf(buf, PAGE_SIZE, "%#x\n", info.default_color); | ||
110 | } | 112 | } |
111 | 113 | ||
112 | static ssize_t manager_default_color_store(struct omap_overlay_manager *mgr, | 114 | static ssize_t manager_default_color_store(struct omap_overlay_manager *mgr, |
@@ -144,8 +146,11 @@ static ssize_t manager_trans_key_type_show(struct omap_overlay_manager *mgr, | |||
144 | char *buf) | 146 | char *buf) |
145 | { | 147 | { |
146 | enum omap_dss_trans_key_type key_type; | 148 | enum omap_dss_trans_key_type key_type; |
149 | struct omap_overlay_manager_info info; | ||
150 | |||
151 | mgr->get_manager_info(mgr, &info); | ||
147 | 152 | ||
148 | key_type = mgr->info.trans_key_type; | 153 | key_type = info.trans_key_type; |
149 | BUG_ON(key_type >= ARRAY_SIZE(trans_key_type_str)); | 154 | BUG_ON(key_type >= ARRAY_SIZE(trans_key_type_str)); |
150 | 155 | ||
151 | return snprintf(buf, PAGE_SIZE, "%s\n", trans_key_type_str[key_type]); | 156 | return snprintf(buf, PAGE_SIZE, "%s\n", trans_key_type_str[key_type]); |
@@ -185,7 +190,11 @@ static ssize_t manager_trans_key_type_store(struct omap_overlay_manager *mgr, | |||
185 | static ssize_t manager_trans_key_value_show(struct omap_overlay_manager *mgr, | 190 | static ssize_t manager_trans_key_value_show(struct omap_overlay_manager *mgr, |
186 | char *buf) | 191 | char *buf) |
187 | { | 192 | { |
188 | return snprintf(buf, PAGE_SIZE, "%#x\n", mgr->info.trans_key); | 193 | struct omap_overlay_manager_info info; |
194 | |||
195 | mgr->get_manager_info(mgr, &info); | ||
196 | |||
197 | return snprintf(buf, PAGE_SIZE, "%#x\n", info.trans_key); | ||
189 | } | 198 | } |
190 | 199 | ||
191 | static ssize_t manager_trans_key_value_store(struct omap_overlay_manager *mgr, | 200 | static ssize_t manager_trans_key_value_store(struct omap_overlay_manager *mgr, |
@@ -217,7 +226,11 @@ static ssize_t manager_trans_key_value_store(struct omap_overlay_manager *mgr, | |||
217 | static ssize_t manager_trans_key_enabled_show(struct omap_overlay_manager *mgr, | 226 | static ssize_t manager_trans_key_enabled_show(struct omap_overlay_manager *mgr, |
218 | char *buf) | 227 | char *buf) |
219 | { | 228 | { |
220 | return snprintf(buf, PAGE_SIZE, "%d\n", mgr->info.trans_enabled); | 229 | struct omap_overlay_manager_info info; |
230 | |||
231 | mgr->get_manager_info(mgr, &info); | ||
232 | |||
233 | return snprintf(buf, PAGE_SIZE, "%d\n", info.trans_enabled); | ||
221 | } | 234 | } |
222 | 235 | ||
223 | static ssize_t manager_trans_key_enabled_store(struct omap_overlay_manager *mgr, | 236 | static ssize_t manager_trans_key_enabled_store(struct omap_overlay_manager *mgr, |
@@ -249,10 +262,14 @@ static ssize_t manager_trans_key_enabled_store(struct omap_overlay_manager *mgr, | |||
249 | static ssize_t manager_alpha_blending_enabled_show( | 262 | static ssize_t manager_alpha_blending_enabled_show( |
250 | struct omap_overlay_manager *mgr, char *buf) | 263 | struct omap_overlay_manager *mgr, char *buf) |
251 | { | 264 | { |
265 | struct omap_overlay_manager_info info; | ||
266 | |||
267 | mgr->get_manager_info(mgr, &info); | ||
268 | |||
252 | WARN_ON(!dss_has_feature(FEAT_ALPHA_FIXED_ZORDER)); | 269 | WARN_ON(!dss_has_feature(FEAT_ALPHA_FIXED_ZORDER)); |
253 | 270 | ||
254 | return snprintf(buf, PAGE_SIZE, "%d\n", | 271 | return snprintf(buf, PAGE_SIZE, "%d\n", |
255 | mgr->info.partial_alpha_enabled); | 272 | info.partial_alpha_enabled); |
256 | } | 273 | } |
257 | 274 | ||
258 | static ssize_t manager_alpha_blending_enabled_store( | 275 | static ssize_t manager_alpha_blending_enabled_store( |
@@ -287,7 +304,11 @@ static ssize_t manager_alpha_blending_enabled_store( | |||
287 | static ssize_t manager_cpr_enable_show(struct omap_overlay_manager *mgr, | 304 | static ssize_t manager_cpr_enable_show(struct omap_overlay_manager *mgr, |
288 | char *buf) | 305 | char *buf) |
289 | { | 306 | { |
290 | return snprintf(buf, PAGE_SIZE, "%d\n", mgr->info.cpr_enable); | 307 | struct omap_overlay_manager_info info; |
308 | |||
309 | mgr->get_manager_info(mgr, &info); | ||
310 | |||
311 | return snprintf(buf, PAGE_SIZE, "%d\n", info.cpr_enable); | ||
291 | } | 312 | } |
292 | 313 | ||
293 | static ssize_t manager_cpr_enable_store(struct omap_overlay_manager *mgr, | 314 | static ssize_t manager_cpr_enable_store(struct omap_overlay_manager *mgr, |
@@ -469,143 +490,6 @@ static struct kobj_type manager_ktype = { | |||
469 | .default_attrs = manager_sysfs_attrs, | 490 | .default_attrs = manager_sysfs_attrs, |
470 | }; | 491 | }; |
471 | 492 | ||
472 | /* | ||
473 | * We have 4 levels of cache for the dispc settings. First two are in SW and | ||
474 | * the latter two in HW. | ||
475 | * | ||
476 | * +--------------------+ | ||
477 | * |overlay/manager_info| | ||
478 | * +--------------------+ | ||
479 | * v | ||
480 | * apply() | ||
481 | * v | ||
482 | * +--------------------+ | ||
483 | * | dss_cache | | ||
484 | * +--------------------+ | ||
485 | * v | ||
486 | * configure() | ||
487 | * v | ||
488 | * +--------------------+ | ||
489 | * | shadow registers | | ||
490 | * +--------------------+ | ||
491 | * v | ||
492 | * VFP or lcd/digit_enable | ||
493 | * v | ||
494 | * +--------------------+ | ||
495 | * | registers | | ||
496 | * +--------------------+ | ||
497 | */ | ||
498 | |||
499 | struct overlay_cache_data { | ||
500 | /* If true, cache changed, but not written to shadow registers. Set | ||
501 | * in apply(), cleared when registers written. */ | ||
502 | bool dirty; | ||
503 | /* If true, shadow registers contain changed values not yet in real | ||
504 | * registers. Set when writing to shadow registers, cleared at | ||
505 | * VSYNC/EVSYNC */ | ||
506 | bool shadow_dirty; | ||
507 | |||
508 | bool enabled; | ||
509 | |||
510 | struct omap_overlay_info info; | ||
511 | |||
512 | enum omap_channel channel; | ||
513 | bool replication; | ||
514 | bool ilace; | ||
515 | |||
516 | u32 fifo_low; | ||
517 | u32 fifo_high; | ||
518 | }; | ||
519 | |||
520 | struct manager_cache_data { | ||
521 | /* If true, cache changed, but not written to shadow registers. Set | ||
522 | * in apply(), cleared when registers written. */ | ||
523 | bool dirty; | ||
524 | /* If true, shadow registers contain changed values not yet in real | ||
525 | * registers. Set when writing to shadow registers, cleared at | ||
526 | * VSYNC/EVSYNC */ | ||
527 | bool shadow_dirty; | ||
528 | |||
529 | struct omap_overlay_manager_info info; | ||
530 | |||
531 | bool manual_update; | ||
532 | bool do_manual_update; | ||
533 | |||
534 | /* manual update region */ | ||
535 | u16 x, y, w, h; | ||
536 | |||
537 | /* enlarge the update area if the update area contains scaled | ||
538 | * overlays */ | ||
539 | bool enlarge_update_area; | ||
540 | }; | ||
541 | |||
542 | static struct { | ||
543 | spinlock_t lock; | ||
544 | struct overlay_cache_data overlay_cache[MAX_DSS_OVERLAYS]; | ||
545 | struct manager_cache_data manager_cache[MAX_DSS_MANAGERS]; | ||
546 | |||
547 | bool irq_enabled; | ||
548 | } dss_cache; | ||
549 | |||
550 | |||
551 | |||
552 | static int omap_dss_set_device(struct omap_overlay_manager *mgr, | ||
553 | struct omap_dss_device *dssdev) | ||
554 | { | ||
555 | int i; | ||
556 | int r; | ||
557 | |||
558 | if (dssdev->manager) { | ||
559 | DSSERR("display '%s' already has a manager '%s'\n", | ||
560 | dssdev->name, dssdev->manager->name); | ||
561 | return -EINVAL; | ||
562 | } | ||
563 | |||
564 | if ((mgr->supported_displays & dssdev->type) == 0) { | ||
565 | DSSERR("display '%s' does not support manager '%s'\n", | ||
566 | dssdev->name, mgr->name); | ||
567 | return -EINVAL; | ||
568 | } | ||
569 | |||
570 | for (i = 0; i < mgr->num_overlays; i++) { | ||
571 | struct omap_overlay *ovl = mgr->overlays[i]; | ||
572 | |||
573 | if (ovl->manager != mgr || !ovl->info.enabled) | ||
574 | continue; | ||
575 | |||
576 | r = dss_check_overlay(ovl, dssdev); | ||
577 | if (r) | ||
578 | return r; | ||
579 | } | ||
580 | |||
581 | dssdev->manager = mgr; | ||
582 | mgr->device = dssdev; | ||
583 | mgr->device_changed = true; | ||
584 | |||
585 | return 0; | ||
586 | } | ||
587 | |||
588 | static int omap_dss_unset_device(struct omap_overlay_manager *mgr) | ||
589 | { | ||
590 | if (!mgr->device) { | ||
591 | DSSERR("failed to unset display, display not set.\n"); | ||
592 | return -EINVAL; | ||
593 | } | ||
594 | |||
595 | /* | ||
596 | * Don't allow currently enabled displays to have the overlay manager | ||
597 | * pulled out from underneath them | ||
598 | */ | ||
599 | if (mgr->device->state != OMAP_DSS_DISPLAY_DISABLED) | ||
600 | return -EINVAL; | ||
601 | |||
602 | mgr->device->manager = NULL; | ||
603 | mgr->device = NULL; | ||
604 | mgr->device_changed = true; | ||
605 | |||
606 | return 0; | ||
607 | } | ||
608 | |||
609 | static int dss_mgr_wait_for_vsync(struct omap_overlay_manager *mgr) | 493 | static int dss_mgr_wait_for_vsync(struct omap_overlay_manager *mgr) |
610 | { | 494 | { |
611 | unsigned long timeout = msecs_to_jiffies(500); | 495 | unsigned long timeout = msecs_to_jiffies(500); |
@@ -624,1022 +508,169 @@ static int dss_mgr_wait_for_vsync(struct omap_overlay_manager *mgr) | |||
624 | return omap_dispc_wait_for_irq_interruptible_timeout(irq, timeout); | 508 | return omap_dispc_wait_for_irq_interruptible_timeout(irq, timeout); |
625 | } | 509 | } |
626 | 510 | ||
627 | static int dss_mgr_wait_for_go(struct omap_overlay_manager *mgr) | 511 | int dss_init_overlay_managers(struct platform_device *pdev) |
628 | { | ||
629 | unsigned long timeout = msecs_to_jiffies(500); | ||
630 | struct manager_cache_data *mc; | ||
631 | u32 irq; | ||
632 | int r; | ||
633 | int i; | ||
634 | struct omap_dss_device *dssdev = mgr->device; | ||
635 | |||
636 | if (!dssdev || dssdev->state != OMAP_DSS_DISPLAY_ACTIVE) | ||
637 | return 0; | ||
638 | |||
639 | if (dssdev->caps & OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE) | ||
640 | return 0; | ||
641 | |||
642 | if (dssdev->type == OMAP_DISPLAY_TYPE_VENC | ||
643 | || dssdev->type == OMAP_DISPLAY_TYPE_HDMI) { | ||
644 | irq = DISPC_IRQ_EVSYNC_ODD | DISPC_IRQ_EVSYNC_EVEN; | ||
645 | } else { | ||
646 | irq = (dssdev->manager->id == OMAP_DSS_CHANNEL_LCD) ? | ||
647 | DISPC_IRQ_VSYNC : DISPC_IRQ_VSYNC2; | ||
648 | } | ||
649 | |||
650 | mc = &dss_cache.manager_cache[mgr->id]; | ||
651 | i = 0; | ||
652 | while (1) { | ||
653 | unsigned long flags; | ||
654 | bool shadow_dirty, dirty; | ||
655 | |||
656 | spin_lock_irqsave(&dss_cache.lock, flags); | ||
657 | dirty = mc->dirty; | ||
658 | shadow_dirty = mc->shadow_dirty; | ||
659 | spin_unlock_irqrestore(&dss_cache.lock, flags); | ||
660 | |||
661 | if (!dirty && !shadow_dirty) { | ||
662 | r = 0; | ||
663 | break; | ||
664 | } | ||
665 | |||
666 | /* 4 iterations is the worst case: | ||
667 | * 1 - initial iteration, dirty = true (between VFP and VSYNC) | ||
668 | * 2 - first VSYNC, dirty = true | ||
669 | * 3 - dirty = false, shadow_dirty = true | ||
670 | * 4 - shadow_dirty = false */ | ||
671 | if (i++ == 3) { | ||
672 | DSSERR("mgr(%d)->wait_for_go() not finishing\n", | ||
673 | mgr->id); | ||
674 | r = 0; | ||
675 | break; | ||
676 | } | ||
677 | |||
678 | r = omap_dispc_wait_for_irq_interruptible_timeout(irq, timeout); | ||
679 | if (r == -ERESTARTSYS) | ||
680 | break; | ||
681 | |||
682 | if (r) { | ||
683 | DSSERR("mgr(%d)->wait_for_go() timeout\n", mgr->id); | ||
684 | break; | ||
685 | } | ||
686 | } | ||
687 | |||
688 | return r; | ||
689 | } | ||
690 | |||
691 | int dss_mgr_wait_for_go_ovl(struct omap_overlay *ovl) | ||
692 | { | ||
693 | unsigned long timeout = msecs_to_jiffies(500); | ||
694 | struct overlay_cache_data *oc; | ||
695 | struct omap_dss_device *dssdev; | ||
696 | u32 irq; | ||
697 | int r; | ||
698 | int i; | ||
699 | |||
700 | if (!ovl->manager) | ||
701 | return 0; | ||
702 | |||
703 | dssdev = ovl->manager->device; | ||
704 | |||
705 | if (!dssdev || dssdev->state != OMAP_DSS_DISPLAY_ACTIVE) | ||
706 | return 0; | ||
707 | |||
708 | if (dssdev->caps & OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE) | ||
709 | return 0; | ||
710 | |||
711 | if (dssdev->type == OMAP_DISPLAY_TYPE_VENC | ||
712 | || dssdev->type == OMAP_DISPLAY_TYPE_HDMI) { | ||
713 | irq = DISPC_IRQ_EVSYNC_ODD | DISPC_IRQ_EVSYNC_EVEN; | ||
714 | } else { | ||
715 | irq = (dssdev->manager->id == OMAP_DSS_CHANNEL_LCD) ? | ||
716 | DISPC_IRQ_VSYNC : DISPC_IRQ_VSYNC2; | ||
717 | } | ||
718 | |||
719 | oc = &dss_cache.overlay_cache[ovl->id]; | ||
720 | i = 0; | ||
721 | while (1) { | ||
722 | unsigned long flags; | ||
723 | bool shadow_dirty, dirty; | ||
724 | |||
725 | spin_lock_irqsave(&dss_cache.lock, flags); | ||
726 | dirty = oc->dirty; | ||
727 | shadow_dirty = oc->shadow_dirty; | ||
728 | spin_unlock_irqrestore(&dss_cache.lock, flags); | ||
729 | |||
730 | if (!dirty && !shadow_dirty) { | ||
731 | r = 0; | ||
732 | break; | ||
733 | } | ||
734 | |||
735 | /* 4 iterations is the worst case: | ||
736 | * 1 - initial iteration, dirty = true (between VFP and VSYNC) | ||
737 | * 2 - first VSYNC, dirty = true | ||
738 | * 3 - dirty = false, shadow_dirty = true | ||
739 | * 4 - shadow_dirty = false */ | ||
740 | if (i++ == 3) { | ||
741 | DSSERR("ovl(%d)->wait_for_go() not finishing\n", | ||
742 | ovl->id); | ||
743 | r = 0; | ||
744 | break; | ||
745 | } | ||
746 | |||
747 | r = omap_dispc_wait_for_irq_interruptible_timeout(irq, timeout); | ||
748 | if (r == -ERESTARTSYS) | ||
749 | break; | ||
750 | |||
751 | if (r) { | ||
752 | DSSERR("ovl(%d)->wait_for_go() timeout\n", ovl->id); | ||
753 | break; | ||
754 | } | ||
755 | } | ||
756 | |||
757 | return r; | ||
758 | } | ||
759 | |||
760 | static int overlay_enabled(struct omap_overlay *ovl) | ||
761 | { | ||
762 | return ovl->info.enabled && ovl->manager && ovl->manager->device; | ||
763 | } | ||
764 | |||
765 | /* Is rect1 a subset of rect2? */ | ||
766 | static bool rectangle_subset(int x1, int y1, int w1, int h1, | ||
767 | int x2, int y2, int w2, int h2) | ||
768 | { | ||
769 | if (x1 < x2 || y1 < y2) | ||
770 | return false; | ||
771 | |||
772 | if (x1 + w1 > x2 + w2) | ||
773 | return false; | ||
774 | |||
775 | if (y1 + h1 > y2 + h2) | ||
776 | return false; | ||
777 | |||
778 | return true; | ||
779 | } | ||
780 | |||
781 | /* Do rect1 and rect2 overlap? */ | ||
782 | static bool rectangle_intersects(int x1, int y1, int w1, int h1, | ||
783 | int x2, int y2, int w2, int h2) | ||
784 | { | ||
785 | if (x1 >= x2 + w2) | ||
786 | return false; | ||
787 | |||
788 | if (x2 >= x1 + w1) | ||
789 | return false; | ||
790 | |||
791 | if (y1 >= y2 + h2) | ||
792 | return false; | ||
793 | |||
794 | if (y2 >= y1 + h1) | ||
795 | return false; | ||
796 | |||
797 | return true; | ||
798 | } | ||
799 | |||
800 | static bool dispc_is_overlay_scaled(struct overlay_cache_data *oc) | ||
801 | { | ||
802 | struct omap_overlay_info *oi = &oc->info; | ||
803 | |||
804 | if (oi->out_width != 0 && oi->width != oi->out_width) | ||
805 | return true; | ||
806 | |||
807 | if (oi->out_height != 0 && oi->height != oi->out_height) | ||
808 | return true; | ||
809 | |||
810 | return false; | ||
811 | } | ||
812 | |||
813 | static int configure_overlay(enum omap_plane plane) | ||
814 | { | 512 | { |
815 | struct overlay_cache_data *c; | 513 | int i, r; |
816 | struct manager_cache_data *mc; | ||
817 | struct omap_overlay_info *oi, new_oi; | ||
818 | struct omap_overlay_manager_info *mi; | ||
819 | u16 outw, outh; | ||
820 | u16 x, y, w, h; | ||
821 | u32 paddr; | ||
822 | int r; | ||
823 | u16 orig_w, orig_h, orig_outw, orig_outh; | ||
824 | 514 | ||
825 | DSSDBGF("%d", plane); | 515 | num_managers = dss_feat_get_num_mgrs(); |
826 | 516 | ||
827 | c = &dss_cache.overlay_cache[plane]; | 517 | managers = kzalloc(sizeof(struct omap_overlay_manager) * num_managers, |
828 | oi = &c->info; | 518 | GFP_KERNEL); |
829 | 519 | ||
830 | if (!c->enabled) { | 520 | BUG_ON(managers == NULL); |
831 | dispc_ovl_enable(plane, 0); | ||
832 | return 0; | ||
833 | } | ||
834 | 521 | ||
835 | mc = &dss_cache.manager_cache[c->channel]; | 522 | for (i = 0; i < num_managers; ++i) { |
836 | mi = &mc->info; | 523 | struct omap_overlay_manager *mgr = &managers[i]; |
837 | |||
838 | x = oi->pos_x; | ||
839 | y = oi->pos_y; | ||
840 | w = oi->width; | ||
841 | h = oi->height; | ||
842 | outw = oi->out_width == 0 ? oi->width : oi->out_width; | ||
843 | outh = oi->out_height == 0 ? oi->height : oi->out_height; | ||
844 | paddr = oi->paddr; | ||
845 | |||
846 | orig_w = w; | ||
847 | orig_h = h; | ||
848 | orig_outw = outw; | ||
849 | orig_outh = outh; | ||
850 | |||
851 | if (mc->manual_update && mc->do_manual_update) { | ||
852 | unsigned bpp; | ||
853 | unsigned scale_x_m = w, scale_x_d = outw; | ||
854 | unsigned scale_y_m = h, scale_y_d = outh; | ||
855 | |||
856 | /* If the overlay is outside the update region, disable it */ | ||
857 | if (!rectangle_intersects(mc->x, mc->y, mc->w, mc->h, | ||
858 | x, y, outw, outh)) { | ||
859 | dispc_ovl_enable(plane, 0); | ||
860 | return 0; | ||
861 | } | ||
862 | 524 | ||
863 | switch (oi->color_mode) { | 525 | switch (i) { |
864 | case OMAP_DSS_COLOR_NV12: | 526 | case 0: |
865 | bpp = 8; | 527 | mgr->name = "lcd"; |
866 | break; | 528 | mgr->id = OMAP_DSS_CHANNEL_LCD; |
867 | case OMAP_DSS_COLOR_RGB16: | ||
868 | case OMAP_DSS_COLOR_ARGB16: | ||
869 | case OMAP_DSS_COLOR_YUV2: | ||
870 | case OMAP_DSS_COLOR_UYVY: | ||
871 | case OMAP_DSS_COLOR_RGBA16: | ||
872 | case OMAP_DSS_COLOR_RGBX16: | ||
873 | case OMAP_DSS_COLOR_ARGB16_1555: | ||
874 | case OMAP_DSS_COLOR_XRGB16_1555: | ||
875 | bpp = 16; | ||
876 | break; | 529 | break; |
877 | 530 | case 1: | |
878 | case OMAP_DSS_COLOR_RGB24P: | 531 | mgr->name = "tv"; |
879 | bpp = 24; | 532 | mgr->id = OMAP_DSS_CHANNEL_DIGIT; |
880 | break; | 533 | break; |
881 | 534 | case 2: | |
882 | case OMAP_DSS_COLOR_RGB24U: | 535 | mgr->name = "lcd2"; |
883 | case OMAP_DSS_COLOR_ARGB32: | 536 | mgr->id = OMAP_DSS_CHANNEL_LCD2; |
884 | case OMAP_DSS_COLOR_RGBA32: | ||
885 | case OMAP_DSS_COLOR_RGBX32: | ||
886 | bpp = 32; | ||
887 | break; | 537 | break; |
888 | |||
889 | default: | ||
890 | BUG(); | ||
891 | } | 538 | } |
892 | 539 | ||
893 | if (mc->x > oi->pos_x) { | 540 | mgr->set_device = &dss_mgr_set_device; |
894 | x = 0; | 541 | mgr->unset_device = &dss_mgr_unset_device; |
895 | outw -= (mc->x - oi->pos_x); | 542 | mgr->apply = &omap_dss_mgr_apply; |
896 | paddr += (mc->x - oi->pos_x) * | 543 | mgr->set_manager_info = &dss_mgr_set_info; |
897 | scale_x_m / scale_x_d * bpp / 8; | 544 | mgr->get_manager_info = &dss_mgr_get_info; |
898 | } else { | 545 | mgr->wait_for_go = &dss_mgr_wait_for_go; |
899 | x = oi->pos_x - mc->x; | 546 | mgr->wait_for_vsync = &dss_mgr_wait_for_vsync; |
900 | } | ||
901 | |||
902 | if (mc->y > oi->pos_y) { | ||
903 | y = 0; | ||
904 | outh -= (mc->y - oi->pos_y); | ||
905 | paddr += (mc->y - oi->pos_y) * | ||
906 | scale_y_m / scale_y_d * | ||
907 | oi->screen_width * bpp / 8; | ||
908 | } else { | ||
909 | y = oi->pos_y - mc->y; | ||
910 | } | ||
911 | |||
912 | if (mc->w < (x + outw)) | ||
913 | outw -= (x + outw) - (mc->w); | ||
914 | |||
915 | if (mc->h < (y + outh)) | ||
916 | outh -= (y + outh) - (mc->h); | ||
917 | |||
918 | w = w * outw / orig_outw; | ||
919 | h = h * outh / orig_outh; | ||
920 | |||
921 | /* YUV mode overlay's input width has to be even and the | ||
922 | * algorithm above may adjust the width to be odd. | ||
923 | * | ||
924 | * Here we adjust the width if needed, preferring to increase | ||
925 | * the width if the original width was bigger. | ||
926 | */ | ||
927 | if ((w & 1) && | ||
928 | (oi->color_mode == OMAP_DSS_COLOR_YUV2 || | ||
929 | oi->color_mode == OMAP_DSS_COLOR_UYVY)) { | ||
930 | if (orig_w > w) | ||
931 | w += 1; | ||
932 | else | ||
933 | w -= 1; | ||
934 | } | ||
935 | } | ||
936 | |||
937 | new_oi = *oi; | ||
938 | |||
939 | /* update new_oi members which could have been possibly updated */ | ||
940 | new_oi.pos_x = x; | ||
941 | new_oi.pos_y = y; | ||
942 | new_oi.width = w; | ||
943 | new_oi.height = h; | ||
944 | new_oi.out_width = outw; | ||
945 | new_oi.out_height = outh; | ||
946 | new_oi.paddr = paddr; | ||
947 | |||
948 | r = dispc_ovl_setup(plane, &new_oi, c->ilace, c->channel, | ||
949 | c->replication, c->fifo_low, c->fifo_high); | ||
950 | if (r) { | ||
951 | /* this shouldn't happen */ | ||
952 | DSSERR("dispc_ovl_setup failed for ovl %d\n", plane); | ||
953 | dispc_ovl_enable(plane, 0); | ||
954 | return r; | ||
955 | } | ||
956 | |||
957 | dispc_ovl_enable(plane, 1); | ||
958 | |||
959 | return 0; | ||
960 | } | ||
961 | |||
962 | static void configure_manager(enum omap_channel channel) | ||
963 | { | ||
964 | struct omap_overlay_manager_info *mi; | ||
965 | |||
966 | DSSDBGF("%d", channel); | ||
967 | |||
968 | /* picking info from the cache */ | ||
969 | mi = &dss_cache.manager_cache[channel].info; | ||
970 | |||
971 | dispc_mgr_set_default_color(channel, mi->default_color); | ||
972 | dispc_mgr_set_trans_key(channel, mi->trans_key_type, mi->trans_key); | ||
973 | dispc_mgr_enable_trans_key(channel, mi->trans_enabled); | ||
974 | dispc_mgr_enable_alpha_fixed_zorder(channel, mi->partial_alpha_enabled); | ||
975 | if (dss_has_feature(FEAT_CPR)) { | ||
976 | dispc_mgr_enable_cpr(channel, mi->cpr_enable); | ||
977 | dispc_mgr_set_cpr_coef(channel, &mi->cpr_coefs); | ||
978 | } | ||
979 | } | ||
980 | |||
981 | /* configure_dispc() tries to write values from cache to shadow registers. | ||
982 | * It writes only to those managers/overlays that are not busy. | ||
983 | * returns 0 if everything could be written to shadow registers. | ||
984 | * returns 1 if not everything could be written to shadow registers. */ | ||
985 | static int configure_dispc(void) | ||
986 | { | ||
987 | struct overlay_cache_data *oc; | ||
988 | struct manager_cache_data *mc; | ||
989 | const int num_ovls = dss_feat_get_num_ovls(); | ||
990 | const int num_mgrs = dss_feat_get_num_mgrs(); | ||
991 | int i; | ||
992 | int r; | ||
993 | bool mgr_busy[MAX_DSS_MANAGERS]; | ||
994 | bool mgr_go[MAX_DSS_MANAGERS]; | ||
995 | bool busy; | ||
996 | |||
997 | r = 0; | ||
998 | busy = false; | ||
999 | |||
1000 | for (i = 0; i < num_mgrs; i++) { | ||
1001 | mgr_busy[i] = dispc_mgr_go_busy(i); | ||
1002 | mgr_go[i] = false; | ||
1003 | } | ||
1004 | |||
1005 | /* Commit overlay settings */ | ||
1006 | for (i = 0; i < num_ovls; ++i) { | ||
1007 | oc = &dss_cache.overlay_cache[i]; | ||
1008 | mc = &dss_cache.manager_cache[oc->channel]; | ||
1009 | 547 | ||
1010 | if (!oc->dirty) | 548 | mgr->caps = 0; |
1011 | continue; | 549 | mgr->supported_displays = |
550 | dss_feat_get_supported_displays(mgr->id); | ||
1012 | 551 | ||
1013 | if (mc->manual_update && !mc->do_manual_update) | 552 | INIT_LIST_HEAD(&mgr->overlays); |
1014 | continue; | ||
1015 | 553 | ||
1016 | if (mgr_busy[oc->channel]) { | 554 | r = kobject_init_and_add(&mgr->kobj, &manager_ktype, |
1017 | busy = true; | 555 | &pdev->dev.kobj, "manager%d", i); |
1018 | continue; | ||
1019 | } | ||
1020 | 556 | ||
1021 | r = configure_overlay(i); | ||
1022 | if (r) | 557 | if (r) |
1023 | DSSERR("configure_overlay %d failed\n", i); | 558 | DSSERR("failed to create sysfs file\n"); |
1024 | |||
1025 | oc->dirty = false; | ||
1026 | oc->shadow_dirty = true; | ||
1027 | mgr_go[oc->channel] = true; | ||
1028 | } | ||
1029 | |||
1030 | /* Commit manager settings */ | ||
1031 | for (i = 0; i < num_mgrs; ++i) { | ||
1032 | mc = &dss_cache.manager_cache[i]; | ||
1033 | |||
1034 | if (!mc->dirty) | ||
1035 | continue; | ||
1036 | |||
1037 | if (mc->manual_update && !mc->do_manual_update) | ||
1038 | continue; | ||
1039 | |||
1040 | if (mgr_busy[i]) { | ||
1041 | busy = true; | ||
1042 | continue; | ||
1043 | } | ||
1044 | |||
1045 | configure_manager(i); | ||
1046 | mc->dirty = false; | ||
1047 | mc->shadow_dirty = true; | ||
1048 | mgr_go[i] = true; | ||
1049 | } | ||
1050 | |||
1051 | /* set GO */ | ||
1052 | for (i = 0; i < num_mgrs; ++i) { | ||
1053 | mc = &dss_cache.manager_cache[i]; | ||
1054 | |||
1055 | if (!mgr_go[i]) | ||
1056 | continue; | ||
1057 | |||
1058 | /* We don't need GO with manual update display. LCD iface will | ||
1059 | * always be turned off after frame, and new settings will be | ||
1060 | * taken in to use at next update */ | ||
1061 | if (!mc->manual_update) | ||
1062 | dispc_mgr_go(i); | ||
1063 | } | ||
1064 | |||
1065 | if (busy) | ||
1066 | r = 1; | ||
1067 | else | ||
1068 | r = 0; | ||
1069 | |||
1070 | return r; | ||
1071 | } | ||
1072 | |||
1073 | /* Make the coordinates even. There are some strange problems with OMAP and | ||
1074 | * partial DSI update when the update widths are odd. */ | ||
1075 | static void make_even(u16 *x, u16 *w) | ||
1076 | { | ||
1077 | u16 x1, x2; | ||
1078 | |||
1079 | x1 = *x; | ||
1080 | x2 = *x + *w; | ||
1081 | |||
1082 | x1 &= ~1; | ||
1083 | x2 = ALIGN(x2, 2); | ||
1084 | |||
1085 | *x = x1; | ||
1086 | *w = x2 - x1; | ||
1087 | } | ||
1088 | |||
1089 | /* Configure dispc for partial update. Return possibly modified update | ||
1090 | * area */ | ||
1091 | void dss_setup_partial_planes(struct omap_dss_device *dssdev, | ||
1092 | u16 *xi, u16 *yi, u16 *wi, u16 *hi, bool enlarge_update_area) | ||
1093 | { | ||
1094 | struct overlay_cache_data *oc; | ||
1095 | struct manager_cache_data *mc; | ||
1096 | struct omap_overlay_info *oi; | ||
1097 | const int num_ovls = dss_feat_get_num_ovls(); | ||
1098 | struct omap_overlay_manager *mgr; | ||
1099 | int i; | ||
1100 | u16 x, y, w, h; | ||
1101 | unsigned long flags; | ||
1102 | bool area_changed; | ||
1103 | |||
1104 | x = *xi; | ||
1105 | y = *yi; | ||
1106 | w = *wi; | ||
1107 | h = *hi; | ||
1108 | |||
1109 | DSSDBG("dispc_setup_partial_planes %d,%d %dx%d\n", | ||
1110 | *xi, *yi, *wi, *hi); | ||
1111 | |||
1112 | mgr = dssdev->manager; | ||
1113 | |||
1114 | if (!mgr) { | ||
1115 | DSSDBG("no manager\n"); | ||
1116 | return; | ||
1117 | } | 559 | } |
1118 | 560 | ||
1119 | make_even(&x, &w); | 561 | return 0; |
1120 | |||
1121 | spin_lock_irqsave(&dss_cache.lock, flags); | ||
1122 | |||
1123 | /* | ||
1124 | * Execute the outer loop until the inner loop has completed | ||
1125 | * once without increasing the update area. This will ensure that | ||
1126 | * all scaled overlays end up completely within the update area. | ||
1127 | */ | ||
1128 | do { | ||
1129 | area_changed = false; | ||
1130 | |||
1131 | /* We need to show the whole overlay if it is scaled. So look | ||
1132 | * for those, and make the update area larger if found. | ||
1133 | * Also mark the overlay cache dirty */ | ||
1134 | for (i = 0; i < num_ovls; ++i) { | ||
1135 | unsigned x1, y1, x2, y2; | ||
1136 | unsigned outw, outh; | ||
1137 | |||
1138 | oc = &dss_cache.overlay_cache[i]; | ||
1139 | oi = &oc->info; | ||
1140 | |||
1141 | if (oc->channel != mgr->id) | ||
1142 | continue; | ||
1143 | |||
1144 | oc->dirty = true; | ||
1145 | |||
1146 | if (!enlarge_update_area) | ||
1147 | continue; | ||
1148 | |||
1149 | if (!oc->enabled) | ||
1150 | continue; | ||
1151 | |||
1152 | if (!dispc_is_overlay_scaled(oc)) | ||
1153 | continue; | ||
1154 | |||
1155 | outw = oi->out_width == 0 ? | ||
1156 | oi->width : oi->out_width; | ||
1157 | outh = oi->out_height == 0 ? | ||
1158 | oi->height : oi->out_height; | ||
1159 | |||
1160 | /* is the overlay outside the update region? */ | ||
1161 | if (!rectangle_intersects(x, y, w, h, | ||
1162 | oi->pos_x, oi->pos_y, | ||
1163 | outw, outh)) | ||
1164 | continue; | ||
1165 | |||
1166 | /* if the overlay totally inside the update region? */ | ||
1167 | if (rectangle_subset(oi->pos_x, oi->pos_y, outw, outh, | ||
1168 | x, y, w, h)) | ||
1169 | continue; | ||
1170 | |||
1171 | if (x > oi->pos_x) | ||
1172 | x1 = oi->pos_x; | ||
1173 | else | ||
1174 | x1 = x; | ||
1175 | |||
1176 | if (y > oi->pos_y) | ||
1177 | y1 = oi->pos_y; | ||
1178 | else | ||
1179 | y1 = y; | ||
1180 | |||
1181 | if ((x + w) < (oi->pos_x + outw)) | ||
1182 | x2 = oi->pos_x + outw; | ||
1183 | else | ||
1184 | x2 = x + w; | ||
1185 | |||
1186 | if ((y + h) < (oi->pos_y + outh)) | ||
1187 | y2 = oi->pos_y + outh; | ||
1188 | else | ||
1189 | y2 = y + h; | ||
1190 | |||
1191 | x = x1; | ||
1192 | y = y1; | ||
1193 | w = x2 - x1; | ||
1194 | h = y2 - y1; | ||
1195 | |||
1196 | make_even(&x, &w); | ||
1197 | |||
1198 | DSSDBG("changing upd area due to ovl(%d) " | ||
1199 | "scaling %d,%d %dx%d\n", | ||
1200 | i, x, y, w, h); | ||
1201 | |||
1202 | area_changed = true; | ||
1203 | } | ||
1204 | } while (area_changed); | ||
1205 | |||
1206 | mc = &dss_cache.manager_cache[mgr->id]; | ||
1207 | mc->do_manual_update = true; | ||
1208 | mc->enlarge_update_area = enlarge_update_area; | ||
1209 | mc->x = x; | ||
1210 | mc->y = y; | ||
1211 | mc->w = w; | ||
1212 | mc->h = h; | ||
1213 | |||
1214 | configure_dispc(); | ||
1215 | |||
1216 | mc->do_manual_update = false; | ||
1217 | |||
1218 | spin_unlock_irqrestore(&dss_cache.lock, flags); | ||
1219 | |||
1220 | *xi = x; | ||
1221 | *yi = y; | ||
1222 | *wi = w; | ||
1223 | *hi = h; | ||
1224 | } | 562 | } |
1225 | 563 | ||
1226 | void dss_start_update(struct omap_dss_device *dssdev) | 564 | void dss_uninit_overlay_managers(struct platform_device *pdev) |
1227 | { | 565 | { |
1228 | struct manager_cache_data *mc; | ||
1229 | struct overlay_cache_data *oc; | ||
1230 | const int num_ovls = dss_feat_get_num_ovls(); | ||
1231 | const int num_mgrs = dss_feat_get_num_mgrs(); | ||
1232 | struct omap_overlay_manager *mgr; | ||
1233 | int i; | 566 | int i; |
1234 | 567 | ||
1235 | mgr = dssdev->manager; | 568 | for (i = 0; i < num_managers; ++i) { |
569 | struct omap_overlay_manager *mgr = &managers[i]; | ||
1236 | 570 | ||
1237 | for (i = 0; i < num_ovls; ++i) { | 571 | kobject_del(&mgr->kobj); |
1238 | oc = &dss_cache.overlay_cache[i]; | 572 | kobject_put(&mgr->kobj); |
1239 | if (oc->channel != mgr->id) | ||
1240 | continue; | ||
1241 | |||
1242 | oc->shadow_dirty = false; | ||
1243 | } | ||
1244 | |||
1245 | for (i = 0; i < num_mgrs; ++i) { | ||
1246 | mc = &dss_cache.manager_cache[i]; | ||
1247 | if (mgr->id != i) | ||
1248 | continue; | ||
1249 | |||
1250 | mc->shadow_dirty = false; | ||
1251 | } | 573 | } |
1252 | 574 | ||
1253 | dssdev->manager->enable(dssdev->manager); | 575 | kfree(managers); |
576 | managers = NULL; | ||
577 | num_managers = 0; | ||
1254 | } | 578 | } |
1255 | 579 | ||
1256 | static void dss_apply_irq_handler(void *data, u32 mask) | 580 | int omap_dss_get_num_overlay_managers(void) |
1257 | { | 581 | { |
1258 | struct manager_cache_data *mc; | 582 | return num_managers; |
1259 | struct overlay_cache_data *oc; | ||
1260 | const int num_ovls = dss_feat_get_num_ovls(); | ||
1261 | const int num_mgrs = dss_feat_get_num_mgrs(); | ||
1262 | int i, r; | ||
1263 | bool mgr_busy[MAX_DSS_MANAGERS]; | ||
1264 | u32 irq_mask; | ||
1265 | |||
1266 | for (i = 0; i < num_mgrs; i++) | ||
1267 | mgr_busy[i] = dispc_mgr_go_busy(i); | ||
1268 | |||
1269 | spin_lock(&dss_cache.lock); | ||
1270 | |||
1271 | for (i = 0; i < num_ovls; ++i) { | ||
1272 | oc = &dss_cache.overlay_cache[i]; | ||
1273 | if (!mgr_busy[oc->channel]) | ||
1274 | oc->shadow_dirty = false; | ||
1275 | } | ||
1276 | |||
1277 | for (i = 0; i < num_mgrs; ++i) { | ||
1278 | mc = &dss_cache.manager_cache[i]; | ||
1279 | if (!mgr_busy[i]) | ||
1280 | mc->shadow_dirty = false; | ||
1281 | } | ||
1282 | |||
1283 | r = configure_dispc(); | ||
1284 | if (r == 1) | ||
1285 | goto end; | ||
1286 | |||
1287 | /* re-read busy flags */ | ||
1288 | for (i = 0; i < num_mgrs; i++) | ||
1289 | mgr_busy[i] = dispc_mgr_go_busy(i); | ||
1290 | |||
1291 | /* keep running as long as there are busy managers, so that | ||
1292 | * we can collect overlay-applied information */ | ||
1293 | for (i = 0; i < num_mgrs; ++i) { | ||
1294 | if (mgr_busy[i]) | ||
1295 | goto end; | ||
1296 | } | ||
1297 | |||
1298 | irq_mask = DISPC_IRQ_VSYNC | DISPC_IRQ_EVSYNC_ODD | | ||
1299 | DISPC_IRQ_EVSYNC_EVEN; | ||
1300 | if (dss_has_feature(FEAT_MGR_LCD2)) | ||
1301 | irq_mask |= DISPC_IRQ_VSYNC2; | ||
1302 | |||
1303 | omap_dispc_unregister_isr(dss_apply_irq_handler, NULL, irq_mask); | ||
1304 | dss_cache.irq_enabled = false; | ||
1305 | |||
1306 | end: | ||
1307 | spin_unlock(&dss_cache.lock); | ||
1308 | } | 583 | } |
584 | EXPORT_SYMBOL(omap_dss_get_num_overlay_managers); | ||
1309 | 585 | ||
1310 | static int omap_dss_mgr_apply(struct omap_overlay_manager *mgr) | 586 | struct omap_overlay_manager *omap_dss_get_overlay_manager(int num) |
1311 | { | 587 | { |
1312 | struct overlay_cache_data *oc; | 588 | if (num >= num_managers) |
1313 | struct manager_cache_data *mc; | 589 | return NULL; |
1314 | int i; | ||
1315 | struct omap_overlay *ovl; | ||
1316 | int num_planes_enabled = 0; | ||
1317 | bool use_fifomerge; | ||
1318 | unsigned long flags; | ||
1319 | int r; | ||
1320 | |||
1321 | DSSDBG("omap_dss_mgr_apply(%s)\n", mgr->name); | ||
1322 | |||
1323 | r = dispc_runtime_get(); | ||
1324 | if (r) | ||
1325 | return r; | ||
1326 | |||
1327 | spin_lock_irqsave(&dss_cache.lock, flags); | ||
1328 | |||
1329 | /* Configure overlays */ | ||
1330 | for (i = 0; i < omap_dss_get_num_overlays(); ++i) { | ||
1331 | struct omap_dss_device *dssdev; | ||
1332 | |||
1333 | ovl = omap_dss_get_overlay(i); | ||
1334 | |||
1335 | oc = &dss_cache.overlay_cache[ovl->id]; | ||
1336 | |||
1337 | if (ovl->manager_changed) { | ||
1338 | ovl->manager_changed = false; | ||
1339 | ovl->info_dirty = true; | ||
1340 | } | ||
1341 | |||
1342 | if (!overlay_enabled(ovl)) { | ||
1343 | if (oc->enabled) { | ||
1344 | oc->enabled = false; | ||
1345 | oc->dirty = true; | ||
1346 | } | ||
1347 | continue; | ||
1348 | } | ||
1349 | |||
1350 | if (!ovl->info_dirty) { | ||
1351 | if (oc->enabled) | ||
1352 | ++num_planes_enabled; | ||
1353 | continue; | ||
1354 | } | ||
1355 | |||
1356 | dssdev = ovl->manager->device; | ||
1357 | |||
1358 | if (dss_check_overlay(ovl, dssdev)) { | ||
1359 | if (oc->enabled) { | ||
1360 | oc->enabled = false; | ||
1361 | oc->dirty = true; | ||
1362 | } | ||
1363 | continue; | ||
1364 | } | ||
1365 | |||
1366 | ovl->info_dirty = false; | ||
1367 | oc->dirty = true; | ||
1368 | oc->info = ovl->info; | ||
1369 | |||
1370 | oc->replication = | ||
1371 | dss_use_replication(dssdev, ovl->info.color_mode); | ||
1372 | |||
1373 | oc->ilace = dssdev->type == OMAP_DISPLAY_TYPE_VENC; | ||
1374 | |||
1375 | oc->channel = ovl->manager->id; | ||
1376 | |||
1377 | oc->enabled = true; | ||
1378 | |||
1379 | ++num_planes_enabled; | ||
1380 | } | ||
1381 | |||
1382 | /* Configure managers */ | ||
1383 | list_for_each_entry(mgr, &manager_list, list) { | ||
1384 | struct omap_dss_device *dssdev; | ||
1385 | 590 | ||
1386 | mc = &dss_cache.manager_cache[mgr->id]; | 591 | return &managers[num]; |
1387 | |||
1388 | if (mgr->device_changed) { | ||
1389 | mgr->device_changed = false; | ||
1390 | mgr->info_dirty = true; | ||
1391 | } | ||
1392 | |||
1393 | if (!mgr->info_dirty) | ||
1394 | continue; | ||
1395 | |||
1396 | if (!mgr->device) | ||
1397 | continue; | ||
1398 | |||
1399 | dssdev = mgr->device; | ||
1400 | |||
1401 | mgr->info_dirty = false; | ||
1402 | mc->dirty = true; | ||
1403 | mc->info = mgr->info; | ||
1404 | |||
1405 | mc->manual_update = | ||
1406 | dssdev->caps & OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE; | ||
1407 | } | ||
1408 | |||
1409 | /* XXX TODO: Try to get fifomerge working. The problem is that it | ||
1410 | * affects both managers, not individually but at the same time. This | ||
1411 | * means the change has to be well synchronized. I guess the proper way | ||
1412 | * is to have a two step process for fifo merge: | ||
1413 | * fifomerge enable: | ||
1414 | * 1. disable other planes, leaving one plane enabled | ||
1415 | * 2. wait until the planes are disabled on HW | ||
1416 | * 3. config merged fifo thresholds, enable fifomerge | ||
1417 | * fifomerge disable: | ||
1418 | * 1. config unmerged fifo thresholds, disable fifomerge | ||
1419 | * 2. wait until fifo changes are in HW | ||
1420 | * 3. enable planes | ||
1421 | */ | ||
1422 | use_fifomerge = false; | ||
1423 | |||
1424 | /* Configure overlay fifos */ | ||
1425 | for (i = 0; i < omap_dss_get_num_overlays(); ++i) { | ||
1426 | struct omap_dss_device *dssdev; | ||
1427 | u32 size, burst_size; | ||
1428 | |||
1429 | ovl = omap_dss_get_overlay(i); | ||
1430 | |||
1431 | oc = &dss_cache.overlay_cache[ovl->id]; | ||
1432 | |||
1433 | if (!oc->enabled) | ||
1434 | continue; | ||
1435 | |||
1436 | dssdev = ovl->manager->device; | ||
1437 | |||
1438 | size = dispc_ovl_get_fifo_size(ovl->id); | ||
1439 | if (use_fifomerge) | ||
1440 | size *= 3; | ||
1441 | |||
1442 | burst_size = dispc_ovl_get_burst_size(ovl->id); | ||
1443 | |||
1444 | switch (dssdev->type) { | ||
1445 | case OMAP_DISPLAY_TYPE_DPI: | ||
1446 | case OMAP_DISPLAY_TYPE_DBI: | ||
1447 | case OMAP_DISPLAY_TYPE_SDI: | ||
1448 | case OMAP_DISPLAY_TYPE_VENC: | ||
1449 | case OMAP_DISPLAY_TYPE_HDMI: | ||
1450 | default_get_overlay_fifo_thresholds(ovl->id, size, | ||
1451 | burst_size, &oc->fifo_low, | ||
1452 | &oc->fifo_high); | ||
1453 | break; | ||
1454 | #ifdef CONFIG_OMAP2_DSS_DSI | ||
1455 | case OMAP_DISPLAY_TYPE_DSI: | ||
1456 | dsi_get_overlay_fifo_thresholds(ovl->id, size, | ||
1457 | burst_size, &oc->fifo_low, | ||
1458 | &oc->fifo_high); | ||
1459 | break; | ||
1460 | #endif | ||
1461 | default: | ||
1462 | BUG(); | ||
1463 | } | ||
1464 | } | ||
1465 | |||
1466 | r = 0; | ||
1467 | if (!dss_cache.irq_enabled) { | ||
1468 | u32 mask; | ||
1469 | |||
1470 | mask = DISPC_IRQ_VSYNC | DISPC_IRQ_EVSYNC_ODD | | ||
1471 | DISPC_IRQ_EVSYNC_EVEN; | ||
1472 | if (dss_has_feature(FEAT_MGR_LCD2)) | ||
1473 | mask |= DISPC_IRQ_VSYNC2; | ||
1474 | |||
1475 | r = omap_dispc_register_isr(dss_apply_irq_handler, NULL, mask); | ||
1476 | dss_cache.irq_enabled = true; | ||
1477 | } | ||
1478 | configure_dispc(); | ||
1479 | |||
1480 | spin_unlock_irqrestore(&dss_cache.lock, flags); | ||
1481 | |||
1482 | dispc_runtime_put(); | ||
1483 | |||
1484 | return r; | ||
1485 | } | 592 | } |
593 | EXPORT_SYMBOL(omap_dss_get_overlay_manager); | ||
1486 | 594 | ||
1487 | static int dss_check_manager(struct omap_overlay_manager *mgr) | 595 | int dss_mgr_simple_check(struct omap_overlay_manager *mgr, |
596 | const struct omap_overlay_manager_info *info) | ||
1488 | { | 597 | { |
1489 | if (dss_has_feature(FEAT_ALPHA_FIXED_ZORDER)) { | 598 | if (dss_has_feature(FEAT_ALPHA_FIXED_ZORDER)) { |
1490 | /* | 599 | /* |
1491 | * OMAP3 supports only graphics source transparency color key | 600 | * OMAP3 supports only graphics source transparency color key |
1492 | * and alpha blending simultaneously. See TRM 15.4.2.4.2.2 | 601 | * and alpha blending simultaneously. See TRM 15.4.2.4.2.2 |
1493 | * Alpha Mode | 602 | * Alpha Mode. |
1494 | */ | 603 | */ |
1495 | if (mgr->info.partial_alpha_enabled && mgr->info.trans_enabled | 604 | if (info->partial_alpha_enabled && info->trans_enabled |
1496 | && mgr->info.trans_key_type != | 605 | && info->trans_key_type != OMAP_DSS_COLOR_KEY_GFX_DST) { |
1497 | OMAP_DSS_COLOR_KEY_GFX_DST) | 606 | DSSERR("check_manager: illegal transparency key\n"); |
1498 | return -EINVAL; | 607 | return -EINVAL; |
608 | } | ||
1499 | } | 609 | } |
1500 | 610 | ||
1501 | return 0; | 611 | return 0; |
1502 | } | 612 | } |
1503 | 613 | ||
1504 | static int omap_dss_mgr_set_info(struct omap_overlay_manager *mgr, | 614 | static int dss_mgr_check_zorder(struct omap_overlay_manager *mgr, |
1505 | struct omap_overlay_manager_info *info) | 615 | struct omap_overlay_info **overlay_infos) |
1506 | { | ||
1507 | int r; | ||
1508 | struct omap_overlay_manager_info old_info; | ||
1509 | |||
1510 | old_info = mgr->info; | ||
1511 | mgr->info = *info; | ||
1512 | |||
1513 | r = dss_check_manager(mgr); | ||
1514 | if (r) { | ||
1515 | mgr->info = old_info; | ||
1516 | return r; | ||
1517 | } | ||
1518 | |||
1519 | mgr->info_dirty = true; | ||
1520 | |||
1521 | return 0; | ||
1522 | } | ||
1523 | |||
1524 | static void omap_dss_mgr_get_info(struct omap_overlay_manager *mgr, | ||
1525 | struct omap_overlay_manager_info *info) | ||
1526 | { | 616 | { |
1527 | *info = mgr->info; | 617 | struct omap_overlay *ovl1, *ovl2; |
1528 | } | 618 | struct omap_overlay_info *info1, *info2; |
1529 | 619 | ||
1530 | static int dss_mgr_enable(struct omap_overlay_manager *mgr) | 620 | list_for_each_entry(ovl1, &mgr->overlays, list) { |
1531 | { | 621 | info1 = overlay_infos[ovl1->id]; |
1532 | dispc_mgr_enable(mgr->id, 1); | ||
1533 | return 0; | ||
1534 | } | ||
1535 | 622 | ||
1536 | static int dss_mgr_disable(struct omap_overlay_manager *mgr) | 623 | if (info1 == NULL) |
1537 | { | 624 | continue; |
1538 | dispc_mgr_enable(mgr->id, 0); | ||
1539 | return 0; | ||
1540 | } | ||
1541 | |||
1542 | static void omap_dss_add_overlay_manager(struct omap_overlay_manager *manager) | ||
1543 | { | ||
1544 | ++num_managers; | ||
1545 | list_add_tail(&manager->list, &manager_list); | ||
1546 | } | ||
1547 | |||
1548 | int dss_init_overlay_managers(struct platform_device *pdev) | ||
1549 | { | ||
1550 | int i, r; | ||
1551 | |||
1552 | spin_lock_init(&dss_cache.lock); | ||
1553 | |||
1554 | INIT_LIST_HEAD(&manager_list); | ||
1555 | |||
1556 | num_managers = 0; | ||
1557 | |||
1558 | for (i = 0; i < dss_feat_get_num_mgrs(); ++i) { | ||
1559 | struct omap_overlay_manager *mgr; | ||
1560 | mgr = kzalloc(sizeof(*mgr), GFP_KERNEL); | ||
1561 | |||
1562 | BUG_ON(mgr == NULL); | ||
1563 | |||
1564 | switch (i) { | ||
1565 | case 0: | ||
1566 | mgr->name = "lcd"; | ||
1567 | mgr->id = OMAP_DSS_CHANNEL_LCD; | ||
1568 | break; | ||
1569 | case 1: | ||
1570 | mgr->name = "tv"; | ||
1571 | mgr->id = OMAP_DSS_CHANNEL_DIGIT; | ||
1572 | break; | ||
1573 | case 2: | ||
1574 | mgr->name = "lcd2"; | ||
1575 | mgr->id = OMAP_DSS_CHANNEL_LCD2; | ||
1576 | break; | ||
1577 | } | ||
1578 | |||
1579 | mgr->set_device = &omap_dss_set_device; | ||
1580 | mgr->unset_device = &omap_dss_unset_device; | ||
1581 | mgr->apply = &omap_dss_mgr_apply; | ||
1582 | mgr->set_manager_info = &omap_dss_mgr_set_info; | ||
1583 | mgr->get_manager_info = &omap_dss_mgr_get_info; | ||
1584 | mgr->wait_for_go = &dss_mgr_wait_for_go; | ||
1585 | mgr->wait_for_vsync = &dss_mgr_wait_for_vsync; | ||
1586 | |||
1587 | mgr->enable = &dss_mgr_enable; | ||
1588 | mgr->disable = &dss_mgr_disable; | ||
1589 | |||
1590 | mgr->caps = 0; | ||
1591 | mgr->supported_displays = | ||
1592 | dss_feat_get_supported_displays(mgr->id); | ||
1593 | 625 | ||
1594 | dss_overlay_setup_dispc_manager(mgr); | 626 | list_for_each_entry(ovl2, &mgr->overlays, list) { |
627 | if (ovl1 == ovl2) | ||
628 | continue; | ||
1595 | 629 | ||
1596 | omap_dss_add_overlay_manager(mgr); | 630 | info2 = overlay_infos[ovl2->id]; |
1597 | 631 | ||
1598 | r = kobject_init_and_add(&mgr->kobj, &manager_ktype, | 632 | if (info2 == NULL) |
1599 | &pdev->dev.kobj, "manager%d", i); | 633 | continue; |
1600 | 634 | ||
1601 | if (r) { | 635 | if (info1->zorder == info2->zorder) { |
1602 | DSSERR("failed to create sysfs file\n"); | 636 | DSSERR("overlays %d and %d have the same " |
1603 | continue; | 637 | "zorder %d\n", |
638 | ovl1->id, ovl2->id, info1->zorder); | ||
639 | return -EINVAL; | ||
640 | } | ||
1604 | } | 641 | } |
1605 | } | 642 | } |
1606 | 643 | ||
1607 | return 0; | 644 | return 0; |
1608 | } | 645 | } |
1609 | 646 | ||
1610 | void dss_uninit_overlay_managers(struct platform_device *pdev) | 647 | int dss_mgr_check(struct omap_overlay_manager *mgr, |
648 | struct omap_dss_device *dssdev, | ||
649 | struct omap_overlay_manager_info *info, | ||
650 | struct omap_overlay_info **overlay_infos) | ||
1611 | { | 651 | { |
1612 | struct omap_overlay_manager *mgr; | 652 | struct omap_overlay *ovl; |
653 | int r; | ||
1613 | 654 | ||
1614 | while (!list_empty(&manager_list)) { | 655 | if (dss_has_feature(FEAT_ALPHA_FREE_ZORDER)) { |
1615 | mgr = list_first_entry(&manager_list, | 656 | r = dss_mgr_check_zorder(mgr, overlay_infos); |
1616 | struct omap_overlay_manager, list); | 657 | if (r) |
1617 | list_del(&mgr->list); | 658 | return r; |
1618 | kobject_del(&mgr->kobj); | ||
1619 | kobject_put(&mgr->kobj); | ||
1620 | kfree(mgr); | ||
1621 | } | 659 | } |
1622 | 660 | ||
1623 | num_managers = 0; | 661 | list_for_each_entry(ovl, &mgr->overlays, list) { |
1624 | } | 662 | struct omap_overlay_info *oi; |
663 | int r; | ||
1625 | 664 | ||
1626 | int omap_dss_get_num_overlay_managers(void) | 665 | oi = overlay_infos[ovl->id]; |
1627 | { | ||
1628 | return num_managers; | ||
1629 | } | ||
1630 | EXPORT_SYMBOL(omap_dss_get_num_overlay_managers); | ||
1631 | 666 | ||
1632 | struct omap_overlay_manager *omap_dss_get_overlay_manager(int num) | 667 | if (oi == NULL) |
1633 | { | 668 | continue; |
1634 | int i = 0; | ||
1635 | struct omap_overlay_manager *mgr; | ||
1636 | 669 | ||
1637 | list_for_each_entry(mgr, &manager_list, list) { | 670 | r = dss_ovl_check(ovl, oi, dssdev); |
1638 | if (i++ == num) | 671 | if (r) |
1639 | return mgr; | 672 | return r; |
1640 | } | 673 | } |
1641 | 674 | ||
1642 | return NULL; | 675 | return 0; |
1643 | } | 676 | } |
1644 | EXPORT_SYMBOL(omap_dss_get_overlay_manager); | ||
1645 | |||
diff --git a/drivers/video/omap2/dss/overlay.c b/drivers/video/omap2/dss/overlay.c index ab8e40e48759..6e821810deec 100644 --- a/drivers/video/omap2/dss/overlay.c +++ b/drivers/video/omap2/dss/overlay.c | |||
@@ -38,7 +38,7 @@ | |||
38 | #include "dss_features.h" | 38 | #include "dss_features.h" |
39 | 39 | ||
40 | static int num_overlays; | 40 | static int num_overlays; |
41 | static struct list_head overlay_list; | 41 | static struct omap_overlay *overlays; |
42 | 42 | ||
43 | static ssize_t overlay_name_show(struct omap_overlay *ovl, char *buf) | 43 | static ssize_t overlay_name_show(struct omap_overlay *ovl, char *buf) |
44 | { | 44 | { |
@@ -124,19 +124,31 @@ err: | |||
124 | 124 | ||
125 | static ssize_t overlay_input_size_show(struct omap_overlay *ovl, char *buf) | 125 | static ssize_t overlay_input_size_show(struct omap_overlay *ovl, char *buf) |
126 | { | 126 | { |
127 | struct omap_overlay_info info; | ||
128 | |||
129 | ovl->get_overlay_info(ovl, &info); | ||
130 | |||
127 | return snprintf(buf, PAGE_SIZE, "%d,%d\n", | 131 | return snprintf(buf, PAGE_SIZE, "%d,%d\n", |
128 | ovl->info.width, ovl->info.height); | 132 | info.width, info.height); |
129 | } | 133 | } |
130 | 134 | ||
131 | static ssize_t overlay_screen_width_show(struct omap_overlay *ovl, char *buf) | 135 | static ssize_t overlay_screen_width_show(struct omap_overlay *ovl, char *buf) |
132 | { | 136 | { |
133 | return snprintf(buf, PAGE_SIZE, "%d\n", ovl->info.screen_width); | 137 | struct omap_overlay_info info; |
138 | |||
139 | ovl->get_overlay_info(ovl, &info); | ||
140 | |||
141 | return snprintf(buf, PAGE_SIZE, "%d\n", info.screen_width); | ||
134 | } | 142 | } |
135 | 143 | ||
136 | static ssize_t overlay_position_show(struct omap_overlay *ovl, char *buf) | 144 | static ssize_t overlay_position_show(struct omap_overlay *ovl, char *buf) |
137 | { | 145 | { |
146 | struct omap_overlay_info info; | ||
147 | |||
148 | ovl->get_overlay_info(ovl, &info); | ||
149 | |||
138 | return snprintf(buf, PAGE_SIZE, "%d,%d\n", | 150 | return snprintf(buf, PAGE_SIZE, "%d,%d\n", |
139 | ovl->info.pos_x, ovl->info.pos_y); | 151 | info.pos_x, info.pos_y); |
140 | } | 152 | } |
141 | 153 | ||
142 | static ssize_t overlay_position_store(struct omap_overlay *ovl, | 154 | static ssize_t overlay_position_store(struct omap_overlay *ovl, |
@@ -170,8 +182,12 @@ static ssize_t overlay_position_store(struct omap_overlay *ovl, | |||
170 | 182 | ||
171 | static ssize_t overlay_output_size_show(struct omap_overlay *ovl, char *buf) | 183 | static ssize_t overlay_output_size_show(struct omap_overlay *ovl, char *buf) |
172 | { | 184 | { |
185 | struct omap_overlay_info info; | ||
186 | |||
187 | ovl->get_overlay_info(ovl, &info); | ||
188 | |||
173 | return snprintf(buf, PAGE_SIZE, "%d,%d\n", | 189 | return snprintf(buf, PAGE_SIZE, "%d,%d\n", |
174 | ovl->info.out_width, ovl->info.out_height); | 190 | info.out_width, info.out_height); |
175 | } | 191 | } |
176 | 192 | ||
177 | static ssize_t overlay_output_size_store(struct omap_overlay *ovl, | 193 | static ssize_t overlay_output_size_store(struct omap_overlay *ovl, |
@@ -205,7 +221,7 @@ static ssize_t overlay_output_size_store(struct omap_overlay *ovl, | |||
205 | 221 | ||
206 | static ssize_t overlay_enabled_show(struct omap_overlay *ovl, char *buf) | 222 | static ssize_t overlay_enabled_show(struct omap_overlay *ovl, char *buf) |
207 | { | 223 | { |
208 | return snprintf(buf, PAGE_SIZE, "%d\n", ovl->info.enabled); | 224 | return snprintf(buf, PAGE_SIZE, "%d\n", ovl->is_enabled(ovl)); |
209 | } | 225 | } |
210 | 226 | ||
211 | static ssize_t overlay_enabled_store(struct omap_overlay *ovl, const char *buf, | 227 | static ssize_t overlay_enabled_store(struct omap_overlay *ovl, const char *buf, |
@@ -213,33 +229,30 @@ static ssize_t overlay_enabled_store(struct omap_overlay *ovl, const char *buf, | |||
213 | { | 229 | { |
214 | int r; | 230 | int r; |
215 | bool enable; | 231 | bool enable; |
216 | struct omap_overlay_info info; | ||
217 | |||
218 | ovl->get_overlay_info(ovl, &info); | ||
219 | 232 | ||
220 | r = strtobool(buf, &enable); | 233 | r = strtobool(buf, &enable); |
221 | if (r) | 234 | if (r) |
222 | return r; | 235 | return r; |
223 | 236 | ||
224 | info.enabled = enable; | 237 | if (enable) |
238 | r = ovl->enable(ovl); | ||
239 | else | ||
240 | r = ovl->disable(ovl); | ||
225 | 241 | ||
226 | r = ovl->set_overlay_info(ovl, &info); | ||
227 | if (r) | 242 | if (r) |
228 | return r; | 243 | return r; |
229 | 244 | ||
230 | if (ovl->manager) { | ||
231 | r = ovl->manager->apply(ovl->manager); | ||
232 | if (r) | ||
233 | return r; | ||
234 | } | ||
235 | |||
236 | return size; | 245 | return size; |
237 | } | 246 | } |
238 | 247 | ||
239 | static ssize_t overlay_global_alpha_show(struct omap_overlay *ovl, char *buf) | 248 | static ssize_t overlay_global_alpha_show(struct omap_overlay *ovl, char *buf) |
240 | { | 249 | { |
250 | struct omap_overlay_info info; | ||
251 | |||
252 | ovl->get_overlay_info(ovl, &info); | ||
253 | |||
241 | return snprintf(buf, PAGE_SIZE, "%d\n", | 254 | return snprintf(buf, PAGE_SIZE, "%d\n", |
242 | ovl->info.global_alpha); | 255 | info.global_alpha); |
243 | } | 256 | } |
244 | 257 | ||
245 | static ssize_t overlay_global_alpha_store(struct omap_overlay *ovl, | 258 | static ssize_t overlay_global_alpha_store(struct omap_overlay *ovl, |
@@ -276,8 +289,12 @@ static ssize_t overlay_global_alpha_store(struct omap_overlay *ovl, | |||
276 | static ssize_t overlay_pre_mult_alpha_show(struct omap_overlay *ovl, | 289 | static ssize_t overlay_pre_mult_alpha_show(struct omap_overlay *ovl, |
277 | char *buf) | 290 | char *buf) |
278 | { | 291 | { |
292 | struct omap_overlay_info info; | ||
293 | |||
294 | ovl->get_overlay_info(ovl, &info); | ||
295 | |||
279 | return snprintf(buf, PAGE_SIZE, "%d\n", | 296 | return snprintf(buf, PAGE_SIZE, "%d\n", |
280 | ovl->info.pre_mult_alpha); | 297 | info.pre_mult_alpha); |
281 | } | 298 | } |
282 | 299 | ||
283 | static ssize_t overlay_pre_mult_alpha_store(struct omap_overlay *ovl, | 300 | static ssize_t overlay_pre_mult_alpha_store(struct omap_overlay *ovl, |
@@ -313,7 +330,11 @@ static ssize_t overlay_pre_mult_alpha_store(struct omap_overlay *ovl, | |||
313 | 330 | ||
314 | static ssize_t overlay_zorder_show(struct omap_overlay *ovl, char *buf) | 331 | static ssize_t overlay_zorder_show(struct omap_overlay *ovl, char *buf) |
315 | { | 332 | { |
316 | return snprintf(buf, PAGE_SIZE, "%d\n", ovl->info.zorder); | 333 | struct omap_overlay_info info; |
334 | |||
335 | ovl->get_overlay_info(ovl, &info); | ||
336 | |||
337 | return snprintf(buf, PAGE_SIZE, "%d\n", info.zorder); | ||
317 | } | 338 | } |
318 | 339 | ||
319 | static ssize_t overlay_zorder_store(struct omap_overlay *ovl, | 340 | static ssize_t overlay_zorder_store(struct omap_overlay *ovl, |
@@ -430,183 +451,6 @@ static struct kobj_type overlay_ktype = { | |||
430 | .default_attrs = overlay_sysfs_attrs, | 451 | .default_attrs = overlay_sysfs_attrs, |
431 | }; | 452 | }; |
432 | 453 | ||
433 | /* Check if overlay parameters are compatible with display */ | ||
434 | int dss_check_overlay(struct omap_overlay *ovl, struct omap_dss_device *dssdev) | ||
435 | { | ||
436 | struct omap_overlay_info *info; | ||
437 | u16 outw, outh; | ||
438 | u16 dw, dh; | ||
439 | int i; | ||
440 | |||
441 | if (!dssdev) | ||
442 | return 0; | ||
443 | |||
444 | if (!ovl->info.enabled) | ||
445 | return 0; | ||
446 | |||
447 | info = &ovl->info; | ||
448 | |||
449 | if (info->paddr == 0) { | ||
450 | DSSDBG("check_overlay failed: paddr 0\n"); | ||
451 | return -EINVAL; | ||
452 | } | ||
453 | |||
454 | dssdev->driver->get_resolution(dssdev, &dw, &dh); | ||
455 | |||
456 | DSSDBG("check_overlay %d: (%d,%d %dx%d -> %dx%d) disp (%dx%d)\n", | ||
457 | ovl->id, | ||
458 | info->pos_x, info->pos_y, | ||
459 | info->width, info->height, | ||
460 | info->out_width, info->out_height, | ||
461 | dw, dh); | ||
462 | |||
463 | if ((ovl->caps & OMAP_DSS_OVL_CAP_SCALE) == 0) { | ||
464 | outw = info->width; | ||
465 | outh = info->height; | ||
466 | } else { | ||
467 | if (info->out_width == 0) | ||
468 | outw = info->width; | ||
469 | else | ||
470 | outw = info->out_width; | ||
471 | |||
472 | if (info->out_height == 0) | ||
473 | outh = info->height; | ||
474 | else | ||
475 | outh = info->out_height; | ||
476 | } | ||
477 | |||
478 | if (dw < info->pos_x + outw) { | ||
479 | DSSDBG("check_overlay failed 1: %d < %d + %d\n", | ||
480 | dw, info->pos_x, outw); | ||
481 | return -EINVAL; | ||
482 | } | ||
483 | |||
484 | if (dh < info->pos_y + outh) { | ||
485 | DSSDBG("check_overlay failed 2: %d < %d + %d\n", | ||
486 | dh, info->pos_y, outh); | ||
487 | return -EINVAL; | ||
488 | } | ||
489 | |||
490 | if ((ovl->supported_modes & info->color_mode) == 0) { | ||
491 | DSSERR("overlay doesn't support mode %d\n", info->color_mode); | ||
492 | return -EINVAL; | ||
493 | } | ||
494 | |||
495 | if (ovl->caps & OMAP_DSS_OVL_CAP_ZORDER) { | ||
496 | if (info->zorder < 0 || info->zorder > 3) { | ||
497 | DSSERR("zorder out of range: %d\n", | ||
498 | info->zorder); | ||
499 | return -EINVAL; | ||
500 | } | ||
501 | /* | ||
502 | * Check that zorder doesn't match with zorder of any other | ||
503 | * overlay which is enabled and is also connected to the same | ||
504 | * manager | ||
505 | */ | ||
506 | for (i = 0; i < omap_dss_get_num_overlays(); i++) { | ||
507 | struct omap_overlay *tmp_ovl = omap_dss_get_overlay(i); | ||
508 | |||
509 | if (tmp_ovl->id != ovl->id && | ||
510 | tmp_ovl->manager == ovl->manager && | ||
511 | tmp_ovl->info.enabled == true && | ||
512 | tmp_ovl->info.zorder == info->zorder) { | ||
513 | DSSERR("%s and %s have same zorder: %d\n", | ||
514 | ovl->name, tmp_ovl->name, info->zorder); | ||
515 | return -EINVAL; | ||
516 | } | ||
517 | } | ||
518 | } | ||
519 | |||
520 | return 0; | ||
521 | } | ||
522 | |||
523 | static int dss_ovl_set_overlay_info(struct omap_overlay *ovl, | ||
524 | struct omap_overlay_info *info) | ||
525 | { | ||
526 | int r; | ||
527 | struct omap_overlay_info old_info; | ||
528 | |||
529 | old_info = ovl->info; | ||
530 | ovl->info = *info; | ||
531 | |||
532 | if (ovl->manager) { | ||
533 | r = dss_check_overlay(ovl, ovl->manager->device); | ||
534 | if (r) { | ||
535 | ovl->info = old_info; | ||
536 | return r; | ||
537 | } | ||
538 | } | ||
539 | |||
540 | ovl->info_dirty = true; | ||
541 | |||
542 | return 0; | ||
543 | } | ||
544 | |||
545 | static void dss_ovl_get_overlay_info(struct omap_overlay *ovl, | ||
546 | struct omap_overlay_info *info) | ||
547 | { | ||
548 | *info = ovl->info; | ||
549 | } | ||
550 | |||
551 | static int dss_ovl_wait_for_go(struct omap_overlay *ovl) | ||
552 | { | ||
553 | return dss_mgr_wait_for_go_ovl(ovl); | ||
554 | } | ||
555 | |||
556 | static int omap_dss_set_manager(struct omap_overlay *ovl, | ||
557 | struct omap_overlay_manager *mgr) | ||
558 | { | ||
559 | if (!mgr) | ||
560 | return -EINVAL; | ||
561 | |||
562 | if (ovl->manager) { | ||
563 | DSSERR("overlay '%s' already has a manager '%s'\n", | ||
564 | ovl->name, ovl->manager->name); | ||
565 | return -EINVAL; | ||
566 | } | ||
567 | |||
568 | if (ovl->info.enabled) { | ||
569 | DSSERR("overlay has to be disabled to change the manager\n"); | ||
570 | return -EINVAL; | ||
571 | } | ||
572 | |||
573 | ovl->manager = mgr; | ||
574 | ovl->manager_changed = true; | ||
575 | |||
576 | /* XXX: When there is an overlay on a DSI manual update display, and | ||
577 | * the overlay is first disabled, then moved to tv, and enabled, we | ||
578 | * seem to get SYNC_LOST_DIGIT error. | ||
579 | * | ||
580 | * Waiting doesn't seem to help, but updating the manual update display | ||
581 | * after disabling the overlay seems to fix this. This hints that the | ||
582 | * overlay is perhaps somehow tied to the LCD output until the output | ||
583 | * is updated. | ||
584 | * | ||
585 | * Userspace workaround for this is to update the LCD after disabling | ||
586 | * the overlay, but before moving the overlay to TV. | ||
587 | */ | ||
588 | |||
589 | return 0; | ||
590 | } | ||
591 | |||
592 | static int omap_dss_unset_manager(struct omap_overlay *ovl) | ||
593 | { | ||
594 | if (!ovl->manager) { | ||
595 | DSSERR("failed to detach overlay: manager not set\n"); | ||
596 | return -EINVAL; | ||
597 | } | ||
598 | |||
599 | if (ovl->info.enabled) { | ||
600 | DSSERR("overlay has to be disabled to unset the manager\n"); | ||
601 | return -EINVAL; | ||
602 | } | ||
603 | |||
604 | ovl->manager = NULL; | ||
605 | ovl->manager_changed = true; | ||
606 | |||
607 | return 0; | ||
608 | } | ||
609 | |||
610 | int omap_dss_get_num_overlays(void) | 454 | int omap_dss_get_num_overlays(void) |
611 | { | 455 | { |
612 | return num_overlays; | 456 | return num_overlays; |
@@ -615,134 +459,65 @@ EXPORT_SYMBOL(omap_dss_get_num_overlays); | |||
615 | 459 | ||
616 | struct omap_overlay *omap_dss_get_overlay(int num) | 460 | struct omap_overlay *omap_dss_get_overlay(int num) |
617 | { | 461 | { |
618 | int i = 0; | 462 | if (num >= num_overlays) |
619 | struct omap_overlay *ovl; | 463 | return NULL; |
620 | 464 | ||
621 | list_for_each_entry(ovl, &overlay_list, list) { | 465 | return &overlays[num]; |
622 | if (i++ == num) | ||
623 | return ovl; | ||
624 | } | ||
625 | |||
626 | return NULL; | ||
627 | } | 466 | } |
628 | EXPORT_SYMBOL(omap_dss_get_overlay); | 467 | EXPORT_SYMBOL(omap_dss_get_overlay); |
629 | 468 | ||
630 | static void omap_dss_add_overlay(struct omap_overlay *overlay) | ||
631 | { | ||
632 | ++num_overlays; | ||
633 | list_add_tail(&overlay->list, &overlay_list); | ||
634 | } | ||
635 | |||
636 | static struct omap_overlay *dispc_overlays[MAX_DSS_OVERLAYS]; | ||
637 | |||
638 | void dss_overlay_setup_dispc_manager(struct omap_overlay_manager *mgr) | ||
639 | { | ||
640 | mgr->num_overlays = dss_feat_get_num_ovls(); | ||
641 | mgr->overlays = dispc_overlays; | ||
642 | } | ||
643 | |||
644 | #ifdef L4_EXAMPLE | ||
645 | static struct omap_overlay *l4_overlays[1]; | ||
646 | void dss_overlay_setup_l4_manager(struct omap_overlay_manager *mgr) | ||
647 | { | ||
648 | mgr->num_overlays = 1; | ||
649 | mgr->overlays = l4_overlays; | ||
650 | } | ||
651 | #endif | ||
652 | |||
653 | void dss_init_overlays(struct platform_device *pdev) | 469 | void dss_init_overlays(struct platform_device *pdev) |
654 | { | 470 | { |
655 | int i, r; | 471 | int i, r; |
656 | 472 | ||
657 | INIT_LIST_HEAD(&overlay_list); | 473 | num_overlays = dss_feat_get_num_ovls(); |
658 | 474 | ||
659 | num_overlays = 0; | 475 | overlays = kzalloc(sizeof(struct omap_overlay) * num_overlays, |
476 | GFP_KERNEL); | ||
660 | 477 | ||
661 | for (i = 0; i < dss_feat_get_num_ovls(); ++i) { | 478 | BUG_ON(overlays == NULL); |
662 | struct omap_overlay *ovl; | ||
663 | ovl = kzalloc(sizeof(*ovl), GFP_KERNEL); | ||
664 | 479 | ||
665 | BUG_ON(ovl == NULL); | 480 | for (i = 0; i < num_overlays; ++i) { |
481 | struct omap_overlay *ovl = &overlays[i]; | ||
666 | 482 | ||
667 | switch (i) { | 483 | switch (i) { |
668 | case 0: | 484 | case 0: |
669 | ovl->name = "gfx"; | 485 | ovl->name = "gfx"; |
670 | ovl->id = OMAP_DSS_GFX; | 486 | ovl->id = OMAP_DSS_GFX; |
671 | ovl->info.global_alpha = 255; | ||
672 | ovl->info.zorder = 0; | ||
673 | break; | 487 | break; |
674 | case 1: | 488 | case 1: |
675 | ovl->name = "vid1"; | 489 | ovl->name = "vid1"; |
676 | ovl->id = OMAP_DSS_VIDEO1; | 490 | ovl->id = OMAP_DSS_VIDEO1; |
677 | ovl->info.global_alpha = 255; | ||
678 | ovl->info.zorder = | ||
679 | dss_has_feature(FEAT_ALPHA_FREE_ZORDER) ? 3 : 0; | ||
680 | break; | 491 | break; |
681 | case 2: | 492 | case 2: |
682 | ovl->name = "vid2"; | 493 | ovl->name = "vid2"; |
683 | ovl->id = OMAP_DSS_VIDEO2; | 494 | ovl->id = OMAP_DSS_VIDEO2; |
684 | ovl->info.global_alpha = 255; | ||
685 | ovl->info.zorder = | ||
686 | dss_has_feature(FEAT_ALPHA_FREE_ZORDER) ? 2 : 0; | ||
687 | break; | 495 | break; |
688 | case 3: | 496 | case 3: |
689 | ovl->name = "vid3"; | 497 | ovl->name = "vid3"; |
690 | ovl->id = OMAP_DSS_VIDEO3; | 498 | ovl->id = OMAP_DSS_VIDEO3; |
691 | ovl->info.global_alpha = 255; | ||
692 | ovl->info.zorder = | ||
693 | dss_has_feature(FEAT_ALPHA_FREE_ZORDER) ? 1 : 0; | ||
694 | break; | 499 | break; |
695 | } | 500 | } |
696 | 501 | ||
697 | ovl->set_manager = &omap_dss_set_manager; | 502 | ovl->is_enabled = &dss_ovl_is_enabled; |
698 | ovl->unset_manager = &omap_dss_unset_manager; | 503 | ovl->enable = &dss_ovl_enable; |
699 | ovl->set_overlay_info = &dss_ovl_set_overlay_info; | 504 | ovl->disable = &dss_ovl_disable; |
700 | ovl->get_overlay_info = &dss_ovl_get_overlay_info; | 505 | ovl->set_manager = &dss_ovl_set_manager; |
701 | ovl->wait_for_go = &dss_ovl_wait_for_go; | 506 | ovl->unset_manager = &dss_ovl_unset_manager; |
507 | ovl->set_overlay_info = &dss_ovl_set_info; | ||
508 | ovl->get_overlay_info = &dss_ovl_get_info; | ||
509 | ovl->wait_for_go = &dss_mgr_wait_for_go_ovl; | ||
702 | 510 | ||
703 | ovl->caps = dss_feat_get_overlay_caps(ovl->id); | 511 | ovl->caps = dss_feat_get_overlay_caps(ovl->id); |
704 | ovl->supported_modes = | 512 | ovl->supported_modes = |
705 | dss_feat_get_supported_color_modes(ovl->id); | 513 | dss_feat_get_supported_color_modes(ovl->id); |
706 | 514 | ||
707 | omap_dss_add_overlay(ovl); | ||
708 | |||
709 | r = kobject_init_and_add(&ovl->kobj, &overlay_ktype, | 515 | r = kobject_init_and_add(&ovl->kobj, &overlay_ktype, |
710 | &pdev->dev.kobj, "overlay%d", i); | 516 | &pdev->dev.kobj, "overlay%d", i); |
711 | 517 | ||
712 | if (r) { | ||
713 | DSSERR("failed to create sysfs file\n"); | ||
714 | continue; | ||
715 | } | ||
716 | |||
717 | dispc_overlays[i] = ovl; | ||
718 | } | ||
719 | |||
720 | #ifdef L4_EXAMPLE | ||
721 | { | ||
722 | struct omap_overlay *ovl; | ||
723 | ovl = kzalloc(sizeof(*ovl), GFP_KERNEL); | ||
724 | |||
725 | BUG_ON(ovl == NULL); | ||
726 | |||
727 | ovl->name = "l4"; | ||
728 | ovl->supported_modes = OMAP_DSS_COLOR_RGB24U; | ||
729 | |||
730 | ovl->set_manager = &omap_dss_set_manager; | ||
731 | ovl->unset_manager = &omap_dss_unset_manager; | ||
732 | ovl->set_overlay_info = &dss_ovl_set_overlay_info; | ||
733 | ovl->get_overlay_info = &dss_ovl_get_overlay_info; | ||
734 | |||
735 | omap_dss_add_overlay(ovl); | ||
736 | |||
737 | r = kobject_init_and_add(&ovl->kobj, &overlay_ktype, | ||
738 | &pdev->dev.kobj, "overlayl4"); | ||
739 | |||
740 | if (r) | 518 | if (r) |
741 | DSSERR("failed to create sysfs file\n"); | 519 | DSSERR("failed to create sysfs file\n"); |
742 | |||
743 | l4_overlays[0] = ovl; | ||
744 | } | 520 | } |
745 | #endif | ||
746 | } | 521 | } |
747 | 522 | ||
748 | /* connect overlays to the new device, if not already connected. if force | 523 | /* connect overlays to the new device, if not already connected. if force |
@@ -795,8 +570,8 @@ void dss_recheck_connections(struct omap_dss_device *dssdev, bool force) | |||
795 | ovl = omap_dss_get_overlay(i); | 570 | ovl = omap_dss_get_overlay(i); |
796 | if (!ovl->manager || force) { | 571 | if (!ovl->manager || force) { |
797 | if (ovl->manager) | 572 | if (ovl->manager) |
798 | omap_dss_unset_manager(ovl); | 573 | ovl->unset_manager(ovl); |
799 | omap_dss_set_manager(ovl, mgr); | 574 | ovl->set_manager(ovl, mgr); |
800 | } | 575 | } |
801 | } | 576 | } |
802 | 577 | ||
@@ -806,17 +581,95 @@ void dss_recheck_connections(struct omap_dss_device *dssdev, bool force) | |||
806 | 581 | ||
807 | void dss_uninit_overlays(struct platform_device *pdev) | 582 | void dss_uninit_overlays(struct platform_device *pdev) |
808 | { | 583 | { |
809 | struct omap_overlay *ovl; | 584 | int i; |
585 | |||
586 | for (i = 0; i < num_overlays; ++i) { | ||
587 | struct omap_overlay *ovl = &overlays[i]; | ||
810 | 588 | ||
811 | while (!list_empty(&overlay_list)) { | ||
812 | ovl = list_first_entry(&overlay_list, | ||
813 | struct omap_overlay, list); | ||
814 | list_del(&ovl->list); | ||
815 | kobject_del(&ovl->kobj); | 589 | kobject_del(&ovl->kobj); |
816 | kobject_put(&ovl->kobj); | 590 | kobject_put(&ovl->kobj); |
817 | kfree(ovl); | ||
818 | } | 591 | } |
819 | 592 | ||
593 | kfree(overlays); | ||
594 | overlays = NULL; | ||
820 | num_overlays = 0; | 595 | num_overlays = 0; |
821 | } | 596 | } |
822 | 597 | ||
598 | int dss_ovl_simple_check(struct omap_overlay *ovl, | ||
599 | const struct omap_overlay_info *info) | ||
600 | { | ||
601 | if (info->paddr == 0) { | ||
602 | DSSERR("check_overlay: paddr cannot be 0\n"); | ||
603 | return -EINVAL; | ||
604 | } | ||
605 | |||
606 | if ((ovl->caps & OMAP_DSS_OVL_CAP_SCALE) == 0) { | ||
607 | if (info->out_width != 0 && info->width != info->out_width) { | ||
608 | DSSERR("check_overlay: overlay %d doesn't support " | ||
609 | "scaling\n", ovl->id); | ||
610 | return -EINVAL; | ||
611 | } | ||
612 | |||
613 | if (info->out_height != 0 && info->height != info->out_height) { | ||
614 | DSSERR("check_overlay: overlay %d doesn't support " | ||
615 | "scaling\n", ovl->id); | ||
616 | return -EINVAL; | ||
617 | } | ||
618 | } | ||
619 | |||
620 | if ((ovl->supported_modes & info->color_mode) == 0) { | ||
621 | DSSERR("check_overlay: overlay %d doesn't support mode %d\n", | ||
622 | ovl->id, info->color_mode); | ||
623 | return -EINVAL; | ||
624 | } | ||
625 | |||
626 | if (info->zorder >= omap_dss_get_num_overlays()) { | ||
627 | DSSERR("check_overlay: zorder %d too high\n", info->zorder); | ||
628 | return -EINVAL; | ||
629 | } | ||
630 | |||
631 | return 0; | ||
632 | } | ||
633 | |||
634 | int dss_ovl_check(struct omap_overlay *ovl, | ||
635 | struct omap_overlay_info *info, struct omap_dss_device *dssdev) | ||
636 | { | ||
637 | u16 outw, outh; | ||
638 | u16 dw, dh; | ||
639 | |||
640 | if (dssdev == NULL) | ||
641 | return 0; | ||
642 | |||
643 | dssdev->driver->get_resolution(dssdev, &dw, &dh); | ||
644 | |||
645 | if ((ovl->caps & OMAP_DSS_OVL_CAP_SCALE) == 0) { | ||
646 | outw = info->width; | ||
647 | outh = info->height; | ||
648 | } else { | ||
649 | if (info->out_width == 0) | ||
650 | outw = info->width; | ||
651 | else | ||
652 | outw = info->out_width; | ||
653 | |||
654 | if (info->out_height == 0) | ||
655 | outh = info->height; | ||
656 | else | ||
657 | outh = info->out_height; | ||
658 | } | ||
659 | |||
660 | if (dw < info->pos_x + outw) { | ||
661 | DSSERR("overlay %d horizontally not inside the display area " | ||
662 | "(%d + %d >= %d)\n", | ||
663 | ovl->id, info->pos_x, outw, dw); | ||
664 | return -EINVAL; | ||
665 | } | ||
666 | |||
667 | if (dh < info->pos_y + outh) { | ||
668 | DSSERR("overlay %d vertically not inside the display area " | ||
669 | "(%d + %d >= %d)\n", | ||
670 | ovl->id, info->pos_y, outh, dh); | ||
671 | return -EINVAL; | ||
672 | } | ||
673 | |||
674 | return 0; | ||
675 | } | ||
diff --git a/drivers/video/omap2/dss/rfbi.c b/drivers/video/omap2/dss/rfbi.c index 1130c608a561..814bb9500dca 100644 --- a/drivers/video/omap2/dss/rfbi.c +++ b/drivers/video/omap2/dss/rfbi.c | |||
@@ -784,7 +784,6 @@ int omap_rfbi_prepare_update(struct omap_dss_device *dssdev, | |||
784 | if (*w == 0 || *h == 0) | 784 | if (*w == 0 || *h == 0) |
785 | return -EINVAL; | 785 | return -EINVAL; |
786 | 786 | ||
787 | dss_setup_partial_planes(dssdev, x, y, w, h, true); | ||
788 | dispc_mgr_set_lcd_size(dssdev->manager->id, *w, *h); | 787 | dispc_mgr_set_lcd_size(dssdev->manager->id, *w, *h); |
789 | 788 | ||
790 | return 0; | 789 | return 0; |
diff --git a/drivers/video/omap2/dss/sdi.c b/drivers/video/omap2/dss/sdi.c index 40305ad7841e..8266ca0d666b 100644 --- a/drivers/video/omap2/dss/sdi.c +++ b/drivers/video/omap2/dss/sdi.c | |||
@@ -123,10 +123,14 @@ int omapdss_sdi_display_enable(struct omap_dss_device *dssdev) | |||
123 | goto err_sdi_enable; | 123 | goto err_sdi_enable; |
124 | mdelay(2); | 124 | mdelay(2); |
125 | 125 | ||
126 | dssdev->manager->enable(dssdev->manager); | 126 | r = dss_mgr_enable(dssdev->manager); |
127 | if (r) | ||
128 | goto err_mgr_enable; | ||
127 | 129 | ||
128 | return 0; | 130 | return 0; |
129 | 131 | ||
132 | err_mgr_enable: | ||
133 | dss_sdi_disable(); | ||
130 | err_sdi_enable: | 134 | err_sdi_enable: |
131 | err_set_dispc_clock_div: | 135 | err_set_dispc_clock_div: |
132 | err_set_dss_clock_div: | 136 | err_set_dss_clock_div: |
@@ -145,7 +149,7 @@ EXPORT_SYMBOL(omapdss_sdi_display_enable); | |||
145 | 149 | ||
146 | void omapdss_sdi_display_disable(struct omap_dss_device *dssdev) | 150 | void omapdss_sdi_display_disable(struct omap_dss_device *dssdev) |
147 | { | 151 | { |
148 | dssdev->manager->disable(dssdev->manager); | 152 | dss_mgr_disable(dssdev->manager); |
149 | 153 | ||
150 | dss_sdi_disable(); | 154 | dss_sdi_disable(); |
151 | 155 | ||
diff --git a/drivers/video/omap2/dss/ti_hdmi.h b/drivers/video/omap2/dss/ti_hdmi.h index 2c3443dabb14..7503f7f619a7 100644 --- a/drivers/video/omap2/dss/ti_hdmi.h +++ b/drivers/video/omap2/dss/ti_hdmi.h | |||
@@ -110,6 +110,11 @@ struct ti_hdmi_ip_ops { | |||
110 | 110 | ||
111 | void (*dump_phy)(struct hdmi_ip_data *ip_data, struct seq_file *s); | 111 | void (*dump_phy)(struct hdmi_ip_data *ip_data, struct seq_file *s); |
112 | 112 | ||
113 | #if defined(CONFIG_SND_OMAP_SOC_OMAP4_HDMI) || \ | ||
114 | defined(CONFIG_SND_OMAP_SOC_OMAP4_HDMI_MODULE) | ||
115 | void (*audio_enable)(struct hdmi_ip_data *ip_data, bool start); | ||
116 | #endif | ||
117 | |||
113 | }; | 118 | }; |
114 | 119 | ||
115 | struct hdmi_ip_data { | 120 | struct hdmi_ip_data { |
@@ -134,5 +139,8 @@ void ti_hdmi_4xxx_wp_dump(struct hdmi_ip_data *ip_data, struct seq_file *s); | |||
134 | void ti_hdmi_4xxx_pll_dump(struct hdmi_ip_data *ip_data, struct seq_file *s); | 139 | void ti_hdmi_4xxx_pll_dump(struct hdmi_ip_data *ip_data, struct seq_file *s); |
135 | void ti_hdmi_4xxx_core_dump(struct hdmi_ip_data *ip_data, struct seq_file *s); | 140 | void ti_hdmi_4xxx_core_dump(struct hdmi_ip_data *ip_data, struct seq_file *s); |
136 | void ti_hdmi_4xxx_phy_dump(struct hdmi_ip_data *ip_data, struct seq_file *s); | 141 | void ti_hdmi_4xxx_phy_dump(struct hdmi_ip_data *ip_data, struct seq_file *s); |
137 | 142 | #if defined(CONFIG_SND_OMAP_SOC_OMAP4_HDMI) || \ | |
143 | defined(CONFIG_SND_OMAP_SOC_OMAP4_HDMI_MODULE) | ||
144 | void ti_hdmi_4xxx_wp_audio_enable(struct hdmi_ip_data *ip_data, bool enable); | ||
145 | #endif | ||
138 | #endif | 146 | #endif |
diff --git a/drivers/video/omap2/dss/ti_hdmi_4xxx_ip.c b/drivers/video/omap2/dss/ti_hdmi_4xxx_ip.c index e1a6ce518af6..9af81f18f163 100644 --- a/drivers/video/omap2/dss/ti_hdmi_4xxx_ip.c +++ b/drivers/video/omap2/dss/ti_hdmi_4xxx_ip.c | |||
@@ -1204,36 +1204,13 @@ int hdmi_config_audio_acr(struct hdmi_ip_data *ip_data, | |||
1204 | return 0; | 1204 | return 0; |
1205 | } | 1205 | } |
1206 | 1206 | ||
1207 | int hdmi_audio_trigger(struct hdmi_ip_data *ip_data, | 1207 | void ti_hdmi_4xxx_wp_audio_enable(struct hdmi_ip_data *ip_data, bool enable) |
1208 | struct snd_pcm_substream *substream, int cmd, | ||
1209 | struct snd_soc_dai *dai) | ||
1210 | { | 1208 | { |
1211 | int err = 0; | 1209 | REG_FLD_MOD(hdmi_av_base(ip_data), |
1212 | switch (cmd) { | 1210 | HDMI_CORE_AV_AUD_MODE, enable, 0, 0); |
1213 | case SNDRV_PCM_TRIGGER_START: | 1211 | REG_FLD_MOD(hdmi_wp_base(ip_data), |
1214 | case SNDRV_PCM_TRIGGER_RESUME: | 1212 | HDMI_WP_AUDIO_CTRL, enable, 31, 31); |
1215 | case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: | 1213 | REG_FLD_MOD(hdmi_wp_base(ip_data), |
1216 | REG_FLD_MOD(hdmi_av_base(ip_data), | 1214 | HDMI_WP_AUDIO_CTRL, enable, 30, 30); |
1217 | HDMI_CORE_AV_AUD_MODE, 1, 0, 0); | ||
1218 | REG_FLD_MOD(hdmi_wp_base(ip_data), | ||
1219 | HDMI_WP_AUDIO_CTRL, 1, 31, 31); | ||
1220 | REG_FLD_MOD(hdmi_wp_base(ip_data), | ||
1221 | HDMI_WP_AUDIO_CTRL, 1, 30, 30); | ||
1222 | break; | ||
1223 | |||
1224 | case SNDRV_PCM_TRIGGER_STOP: | ||
1225 | case SNDRV_PCM_TRIGGER_SUSPEND: | ||
1226 | case SNDRV_PCM_TRIGGER_PAUSE_PUSH: | ||
1227 | REG_FLD_MOD(hdmi_av_base(ip_data), | ||
1228 | HDMI_CORE_AV_AUD_MODE, 0, 0, 0); | ||
1229 | REG_FLD_MOD(hdmi_wp_base(ip_data), | ||
1230 | HDMI_WP_AUDIO_CTRL, 0, 30, 30); | ||
1231 | REG_FLD_MOD(hdmi_wp_base(ip_data), | ||
1232 | HDMI_WP_AUDIO_CTRL, 0, 31, 31); | ||
1233 | break; | ||
1234 | default: | ||
1235 | err = -EINVAL; | ||
1236 | } | ||
1237 | return err; | ||
1238 | } | 1215 | } |
1239 | #endif | 1216 | #endif |
diff --git a/drivers/video/omap2/dss/ti_hdmi_4xxx_ip.h b/drivers/video/omap2/dss/ti_hdmi_4xxx_ip.h index 204095632d27..a442998980f1 100644 --- a/drivers/video/omap2/dss/ti_hdmi_4xxx_ip.h +++ b/drivers/video/omap2/dss/ti_hdmi_4xxx_ip.h | |||
@@ -576,9 +576,6 @@ struct hdmi_core_audio_config { | |||
576 | 576 | ||
577 | #if defined(CONFIG_SND_OMAP_SOC_OMAP4_HDMI) || \ | 577 | #if defined(CONFIG_SND_OMAP_SOC_OMAP4_HDMI) || \ |
578 | defined(CONFIG_SND_OMAP_SOC_OMAP4_HDMI_MODULE) | 578 | defined(CONFIG_SND_OMAP_SOC_OMAP4_HDMI_MODULE) |
579 | int hdmi_audio_trigger(struct hdmi_ip_data *ip_data, | ||
580 | struct snd_pcm_substream *substream, int cmd, | ||
581 | struct snd_soc_dai *dai); | ||
582 | int hdmi_config_audio_acr(struct hdmi_ip_data *ip_data, | 579 | int hdmi_config_audio_acr(struct hdmi_ip_data *ip_data, |
583 | u32 sample_freq, u32 *n, u32 *cts); | 580 | u32 sample_freq, u32 *n, u32 *cts); |
584 | void hdmi_core_audio_infoframe_config(struct hdmi_ip_data *ip_data, | 581 | void hdmi_core_audio_infoframe_config(struct hdmi_ip_data *ip_data, |
diff --git a/drivers/video/omap2/dss/venc.c b/drivers/video/omap2/dss/venc.c index 7533458ba4d2..b3e9f9091581 100644 --- a/drivers/video/omap2/dss/venc.c +++ b/drivers/video/omap2/dss/venc.c | |||
@@ -417,9 +417,10 @@ static const struct venc_config *venc_timings_to_config( | |||
417 | BUG(); | 417 | BUG(); |
418 | } | 418 | } |
419 | 419 | ||
420 | static void venc_power_on(struct omap_dss_device *dssdev) | 420 | static int venc_power_on(struct omap_dss_device *dssdev) |
421 | { | 421 | { |
422 | u32 l; | 422 | u32 l; |
423 | int r; | ||
423 | 424 | ||
424 | venc_reset(); | 425 | venc_reset(); |
425 | venc_write_config(venc_timings_to_config(&dssdev->panel.timings)); | 426 | venc_write_config(venc_timings_to_config(&dssdev->panel.timings)); |
@@ -447,7 +448,22 @@ static void venc_power_on(struct omap_dss_device *dssdev) | |||
447 | if (dssdev->platform_enable) | 448 | if (dssdev->platform_enable) |
448 | dssdev->platform_enable(dssdev); | 449 | dssdev->platform_enable(dssdev); |
449 | 450 | ||
450 | dssdev->manager->enable(dssdev->manager); | 451 | r = dss_mgr_enable(dssdev->manager); |
452 | if (r) | ||
453 | goto err; | ||
454 | |||
455 | return 0; | ||
456 | |||
457 | err: | ||
458 | venc_write_reg(VENC_OUTPUT_CONTROL, 0); | ||
459 | dss_set_dac_pwrdn_bgz(0); | ||
460 | |||
461 | if (dssdev->platform_disable) | ||
462 | dssdev->platform_disable(dssdev); | ||
463 | |||
464 | regulator_disable(venc.vdda_dac_reg); | ||
465 | |||
466 | return r; | ||
451 | } | 467 | } |
452 | 468 | ||
453 | static void venc_power_off(struct omap_dss_device *dssdev) | 469 | static void venc_power_off(struct omap_dss_device *dssdev) |
@@ -455,7 +471,7 @@ static void venc_power_off(struct omap_dss_device *dssdev) | |||
455 | venc_write_reg(VENC_OUTPUT_CONTROL, 0); | 471 | venc_write_reg(VENC_OUTPUT_CONTROL, 0); |
456 | dss_set_dac_pwrdn_bgz(0); | 472 | dss_set_dac_pwrdn_bgz(0); |
457 | 473 | ||
458 | dssdev->manager->disable(dssdev->manager); | 474 | dss_mgr_disable(dssdev->manager); |
459 | 475 | ||
460 | if (dssdev->platform_disable) | 476 | if (dssdev->platform_disable) |
461 | dssdev->platform_disable(dssdev); | 477 | dssdev->platform_disable(dssdev); |
@@ -504,7 +520,9 @@ static int venc_panel_enable(struct omap_dss_device *dssdev) | |||
504 | if (r) | 520 | if (r) |
505 | goto err1; | 521 | goto err1; |
506 | 522 | ||
507 | venc_power_on(dssdev); | 523 | r = venc_power_on(dssdev); |
524 | if (r) | ||
525 | goto err2; | ||
508 | 526 | ||
509 | venc.wss_data = 0; | 527 | venc.wss_data = 0; |
510 | 528 | ||
@@ -512,6 +530,8 @@ static int venc_panel_enable(struct omap_dss_device *dssdev) | |||
512 | 530 | ||
513 | mutex_unlock(&venc.venc_lock); | 531 | mutex_unlock(&venc.venc_lock); |
514 | return 0; | 532 | return 0; |
533 | err2: | ||
534 | venc_runtime_put(); | ||
515 | err1: | 535 | err1: |
516 | omap_dss_stop_device(dssdev); | 536 | omap_dss_stop_device(dssdev); |
517 | err0: | 537 | err0: |
diff --git a/drivers/video/omap2/omapfb/omapfb-ioctl.c b/drivers/video/omap2/omapfb/omapfb-ioctl.c index df7bcce5b107..16ba6196f330 100644 --- a/drivers/video/omap2/omapfb/omapfb-ioctl.c +++ b/drivers/video/omap2/omapfb/omapfb-ioctl.c | |||
@@ -111,28 +111,22 @@ static int omapfb_setup_plane(struct fb_info *fbi, struct omapfb_plane_info *pi) | |||
111 | set_fb_fix(fbi); | 111 | set_fb_fix(fbi); |
112 | } | 112 | } |
113 | 113 | ||
114 | if (pi->enabled) { | 114 | if (!pi->enabled) { |
115 | struct omap_overlay_info info; | 115 | r = ovl->disable(ovl); |
116 | if (r) | ||
117 | goto undo; | ||
118 | } | ||
116 | 119 | ||
120 | if (pi->enabled) { | ||
117 | r = omapfb_setup_overlay(fbi, ovl, pi->pos_x, pi->pos_y, | 121 | r = omapfb_setup_overlay(fbi, ovl, pi->pos_x, pi->pos_y, |
118 | pi->out_width, pi->out_height); | 122 | pi->out_width, pi->out_height); |
119 | if (r) | 123 | if (r) |
120 | goto undo; | 124 | goto undo; |
121 | |||
122 | ovl->get_overlay_info(ovl, &info); | ||
123 | |||
124 | if (!info.enabled) { | ||
125 | info.enabled = pi->enabled; | ||
126 | r = ovl->set_overlay_info(ovl, &info); | ||
127 | if (r) | ||
128 | goto undo; | ||
129 | } | ||
130 | } else { | 125 | } else { |
131 | struct omap_overlay_info info; | 126 | struct omap_overlay_info info; |
132 | 127 | ||
133 | ovl->get_overlay_info(ovl, &info); | 128 | ovl->get_overlay_info(ovl, &info); |
134 | 129 | ||
135 | info.enabled = pi->enabled; | ||
136 | info.pos_x = pi->pos_x; | 130 | info.pos_x = pi->pos_x; |
137 | info.pos_y = pi->pos_y; | 131 | info.pos_y = pi->pos_y; |
138 | info.out_width = pi->out_width; | 132 | info.out_width = pi->out_width; |
@@ -146,6 +140,12 @@ static int omapfb_setup_plane(struct fb_info *fbi, struct omapfb_plane_info *pi) | |||
146 | if (ovl->manager) | 140 | if (ovl->manager) |
147 | ovl->manager->apply(ovl->manager); | 141 | ovl->manager->apply(ovl->manager); |
148 | 142 | ||
143 | if (pi->enabled) { | ||
144 | r = ovl->enable(ovl); | ||
145 | if (r) | ||
146 | goto undo; | ||
147 | } | ||
148 | |||
149 | /* Release the locks in a specific order to keep lockdep happy */ | 149 | /* Release the locks in a specific order to keep lockdep happy */ |
150 | if (old_rg->id > new_rg->id) { | 150 | if (old_rg->id > new_rg->id) { |
151 | omapfb_put_mem_region(old_rg); | 151 | omapfb_put_mem_region(old_rg); |
@@ -189,19 +189,19 @@ static int omapfb_query_plane(struct fb_info *fbi, struct omapfb_plane_info *pi) | |||
189 | memset(pi, 0, sizeof(*pi)); | 189 | memset(pi, 0, sizeof(*pi)); |
190 | } else { | 190 | } else { |
191 | struct omap_overlay *ovl; | 191 | struct omap_overlay *ovl; |
192 | struct omap_overlay_info *ovli; | 192 | struct omap_overlay_info ovli; |
193 | 193 | ||
194 | ovl = ofbi->overlays[0]; | 194 | ovl = ofbi->overlays[0]; |
195 | ovli = &ovl->info; | 195 | ovl->get_overlay_info(ovl, &ovli); |
196 | 196 | ||
197 | pi->pos_x = ovli->pos_x; | 197 | pi->pos_x = ovli.pos_x; |
198 | pi->pos_y = ovli->pos_y; | 198 | pi->pos_y = ovli.pos_y; |
199 | pi->enabled = ovli->enabled; | 199 | pi->enabled = ovl->is_enabled(ovl); |
200 | pi->channel_out = 0; /* xxx */ | 200 | pi->channel_out = 0; /* xxx */ |
201 | pi->mirror = 0; | 201 | pi->mirror = 0; |
202 | pi->mem_idx = get_mem_idx(ofbi); | 202 | pi->mem_idx = get_mem_idx(ofbi); |
203 | pi->out_width = ovli->out_width; | 203 | pi->out_width = ovli.out_width; |
204 | pi->out_height = ovli->out_height; | 204 | pi->out_height = ovli.out_height; |
205 | } | 205 | } |
206 | 206 | ||
207 | return 0; | 207 | return 0; |
@@ -238,7 +238,9 @@ static int omapfb_setup_mem(struct fb_info *fbi, struct omapfb_mem_info *mi) | |||
238 | continue; | 238 | continue; |
239 | 239 | ||
240 | for (j = 0; j < ofbi2->num_overlays; j++) { | 240 | for (j = 0; j < ofbi2->num_overlays; j++) { |
241 | if (ofbi2->overlays[j]->info.enabled) { | 241 | struct omap_overlay *ovl; |
242 | ovl = ofbi2->overlays[j]; | ||
243 | if (ovl->is_enabled(ovl)) { | ||
242 | r = -EBUSY; | 244 | r = -EBUSY; |
243 | goto out; | 245 | goto out; |
244 | } | 246 | } |
diff --git a/drivers/video/omap2/omapfb/omapfb-main.c b/drivers/video/omap2/omapfb/omapfb-main.c index 68ba1f800082..ce158311ff59 100644 --- a/drivers/video/omap2/omapfb/omapfb-main.c +++ b/drivers/video/omap2/omapfb/omapfb-main.c | |||
@@ -970,16 +970,20 @@ int omapfb_apply_changes(struct fb_info *fbi, int init) | |||
970 | outh = var->yres; | 970 | outh = var->yres; |
971 | } | 971 | } |
972 | } else { | 972 | } else { |
973 | outw = ovl->info.out_width; | 973 | struct omap_overlay_info info; |
974 | outh = ovl->info.out_height; | 974 | ovl->get_overlay_info(ovl, &info); |
975 | outw = info.out_width; | ||
976 | outh = info.out_height; | ||
975 | } | 977 | } |
976 | 978 | ||
977 | if (init) { | 979 | if (init) { |
978 | posx = 0; | 980 | posx = 0; |
979 | posy = 0; | 981 | posy = 0; |
980 | } else { | 982 | } else { |
981 | posx = ovl->info.pos_x; | 983 | struct omap_overlay_info info; |
982 | posy = ovl->info.pos_y; | 984 | ovl->get_overlay_info(ovl, &info); |
985 | posx = info.pos_x; | ||
986 | posy = info.pos_y; | ||
983 | } | 987 | } |
984 | 988 | ||
985 | r = omapfb_setup_overlay(fbi, ovl, posx, posy, outw, outh); | 989 | r = omapfb_setup_overlay(fbi, ovl, posx, posy, outw, outh); |
@@ -2067,6 +2071,8 @@ static int omapfb_create_framebuffers(struct omapfb2_device *fbdev) | |||
2067 | if (ofbi->num_overlays > 0) { | 2071 | if (ofbi->num_overlays > 0) { |
2068 | struct omap_overlay *ovl = ofbi->overlays[0]; | 2072 | struct omap_overlay *ovl = ofbi->overlays[0]; |
2069 | 2073 | ||
2074 | ovl->manager->apply(ovl->manager); | ||
2075 | |||
2070 | r = omapfb_overlay_enable(ovl, 1); | 2076 | r = omapfb_overlay_enable(ovl, 1); |
2071 | 2077 | ||
2072 | if (r) { | 2078 | if (r) { |
diff --git a/drivers/video/omap2/omapfb/omapfb-sysfs.c b/drivers/video/omap2/omapfb/omapfb-sysfs.c index 1694d5148f32..e8d8cc76a435 100644 --- a/drivers/video/omap2/omapfb/omapfb-sysfs.c +++ b/drivers/video/omap2/omapfb/omapfb-sysfs.c | |||
@@ -473,7 +473,9 @@ static ssize_t store_size(struct device *dev, struct device_attribute *attr, | |||
473 | continue; | 473 | continue; |
474 | 474 | ||
475 | for (j = 0; j < ofbi2->num_overlays; j++) { | 475 | for (j = 0; j < ofbi2->num_overlays; j++) { |
476 | if (ofbi2->overlays[j]->info.enabled) { | 476 | struct omap_overlay *ovl; |
477 | ovl = ofbi2->overlays[j]; | ||
478 | if (ovl->is_enabled(ovl)) { | ||
477 | r = -EBUSY; | 479 | r = -EBUSY; |
478 | goto out; | 480 | goto out; |
479 | } | 481 | } |
diff --git a/drivers/video/omap2/omapfb/omapfb.h b/drivers/video/omap2/omapfb/omapfb.h index e12d384ea520..c0bdc9b54ecf 100644 --- a/drivers/video/omap2/omapfb/omapfb.h +++ b/drivers/video/omap2/omapfb/omapfb.h | |||
@@ -181,13 +181,10 @@ static inline void omapfb_unlock(struct omapfb2_device *fbdev) | |||
181 | static inline int omapfb_overlay_enable(struct omap_overlay *ovl, | 181 | static inline int omapfb_overlay_enable(struct omap_overlay *ovl, |
182 | int enable) | 182 | int enable) |
183 | { | 183 | { |
184 | struct omap_overlay_info info; | 184 | if (enable) |
185 | 185 | return ovl->enable(ovl); | |
186 | ovl->get_overlay_info(ovl, &info); | 186 | else |
187 | if (info.enabled == enable) | 187 | return ovl->disable(ovl); |
188 | return 0; | ||
189 | info.enabled = enable; | ||
190 | return ovl->set_overlay_info(ovl, &info); | ||
191 | } | 188 | } |
192 | 189 | ||
193 | static inline struct omapfb2_mem_region * | 190 | static inline struct omapfb2_mem_region * |
diff --git a/drivers/video/pnx4008/pnxrgbfb.c b/drivers/video/pnx4008/pnxrgbfb.c index b2252fea2858..6d30428e9cf9 100644 --- a/drivers/video/pnx4008/pnxrgbfb.c +++ b/drivers/video/pnx4008/pnxrgbfb.c | |||
@@ -193,17 +193,6 @@ static struct platform_driver rgbfb_driver = { | |||
193 | .remove = rgbfb_remove, | 193 | .remove = rgbfb_remove, |
194 | }; | 194 | }; |
195 | 195 | ||
196 | static int __init rgbfb_init(void) | 196 | module_platform_driver(rgbfb_driver); |
197 | { | ||
198 | return platform_driver_register(&rgbfb_driver); | ||
199 | } | ||
200 | |||
201 | static void __exit rgbfb_exit(void) | ||
202 | { | ||
203 | platform_driver_unregister(&rgbfb_driver); | ||
204 | } | ||
205 | |||
206 | module_init(rgbfb_init); | ||
207 | module_exit(rgbfb_exit); | ||
208 | 197 | ||
209 | MODULE_LICENSE("GPL"); | 198 | MODULE_LICENSE("GPL"); |
diff --git a/drivers/video/pnx4008/sdum.c b/drivers/video/pnx4008/sdum.c index 50e00395240f..c5c741452cac 100644 --- a/drivers/video/pnx4008/sdum.c +++ b/drivers/video/pnx4008/sdum.c | |||
@@ -856,17 +856,6 @@ static struct platform_driver sdum_driver = { | |||
856 | .resume = sdum_resume, | 856 | .resume = sdum_resume, |
857 | }; | 857 | }; |
858 | 858 | ||
859 | int __init sdum_init(void) | 859 | module_platform_driver(sdum_driver); |
860 | { | ||
861 | return platform_driver_register(&sdum_driver); | ||
862 | } | ||
863 | |||
864 | static void __exit sdum_exit(void) | ||
865 | { | ||
866 | platform_driver_unregister(&sdum_driver); | ||
867 | }; | ||
868 | |||
869 | module_init(sdum_init); | ||
870 | module_exit(sdum_exit); | ||
871 | 860 | ||
872 | MODULE_LICENSE("GPL"); | 861 | MODULE_LICENSE("GPL"); |
diff --git a/drivers/video/pxa168fb.c b/drivers/video/pxa168fb.c index 18ead6f0184d..8384b941f6ba 100644 --- a/drivers/video/pxa168fb.c +++ b/drivers/video/pxa168fb.c | |||
@@ -832,17 +832,7 @@ static struct platform_driver pxa168fb_driver = { | |||
832 | .remove = __devexit_p(pxa168fb_remove), | 832 | .remove = __devexit_p(pxa168fb_remove), |
833 | }; | 833 | }; |
834 | 834 | ||
835 | static int __init pxa168fb_init(void) | 835 | module_platform_driver(pxa168fb_driver); |
836 | { | ||
837 | return platform_driver_register(&pxa168fb_driver); | ||
838 | } | ||
839 | module_init(pxa168fb_init); | ||
840 | |||
841 | static void __exit pxa168fb_exit(void) | ||
842 | { | ||
843 | platform_driver_unregister(&pxa168fb_driver); | ||
844 | } | ||
845 | module_exit(pxa168fb_exit); | ||
846 | 836 | ||
847 | MODULE_AUTHOR("Lennert Buytenhek <buytenh@marvell.com> " | 837 | MODULE_AUTHOR("Lennert Buytenhek <buytenh@marvell.com> " |
848 | "Green Wan <gwan@marvell.com>"); | 838 | "Green Wan <gwan@marvell.com>"); |
diff --git a/drivers/video/pxa3xx-gcu.c b/drivers/video/pxa3xx-gcu.c index 1ed8b366618d..1d71c08a818f 100644 --- a/drivers/video/pxa3xx-gcu.c +++ b/drivers/video/pxa3xx-gcu.c | |||
@@ -747,20 +747,7 @@ static struct platform_driver pxa3xx_gcu_driver = { | |||
747 | }, | 747 | }, |
748 | }; | 748 | }; |
749 | 749 | ||
750 | static int __init | 750 | module_platform_driver(pxa3xx_gcu_driver); |
751 | pxa3xx_gcu_init(void) | ||
752 | { | ||
753 | return platform_driver_register(&pxa3xx_gcu_driver); | ||
754 | } | ||
755 | |||
756 | static void __exit | ||
757 | pxa3xx_gcu_exit(void) | ||
758 | { | ||
759 | platform_driver_unregister(&pxa3xx_gcu_driver); | ||
760 | } | ||
761 | |||
762 | module_init(pxa3xx_gcu_init); | ||
763 | module_exit(pxa3xx_gcu_exit); | ||
764 | 751 | ||
765 | MODULE_DESCRIPTION("PXA3xx graphics controller unit driver"); | 752 | MODULE_DESCRIPTION("PXA3xx graphics controller unit driver"); |
766 | MODULE_LICENSE("GPL"); | 753 | MODULE_LICENSE("GPL"); |
diff --git a/drivers/video/s3c-fb.c b/drivers/video/s3c-fb.c index 0753b1cfcb8b..0c63b69b6340 100644 --- a/drivers/video/s3c-fb.c +++ b/drivers/video/s3c-fb.c | |||
@@ -192,6 +192,7 @@ struct s3c_fb_vsync { | |||
192 | * @regs: The mapped hardware registers. | 192 | * @regs: The mapped hardware registers. |
193 | * @variant: Variant information for this hardware. | 193 | * @variant: Variant information for this hardware. |
194 | * @enabled: A bitmask of enabled hardware windows. | 194 | * @enabled: A bitmask of enabled hardware windows. |
195 | * @output_on: Flag if the physical output is enabled. | ||
195 | * @pdata: The platform configuration data passed with the device. | 196 | * @pdata: The platform configuration data passed with the device. |
196 | * @windows: The hardware windows that have been claimed. | 197 | * @windows: The hardware windows that have been claimed. |
197 | * @irq_no: IRQ line number | 198 | * @irq_no: IRQ line number |
@@ -208,6 +209,7 @@ struct s3c_fb { | |||
208 | struct s3c_fb_variant variant; | 209 | struct s3c_fb_variant variant; |
209 | 210 | ||
210 | unsigned char enabled; | 211 | unsigned char enabled; |
212 | bool output_on; | ||
211 | 213 | ||
212 | struct s3c_fb_platdata *pdata; | 214 | struct s3c_fb_platdata *pdata; |
213 | struct s3c_fb_win *windows[S3C_FB_MAX_WIN]; | 215 | struct s3c_fb_win *windows[S3C_FB_MAX_WIN]; |
@@ -441,6 +443,39 @@ static void shadow_protect_win(struct s3c_fb_win *win, bool protect) | |||
441 | } | 443 | } |
442 | 444 | ||
443 | /** | 445 | /** |
446 | * s3c_fb_enable() - Set the state of the main LCD output | ||
447 | * @sfb: The main framebuffer state. | ||
448 | * @enable: The state to set. | ||
449 | */ | ||
450 | static void s3c_fb_enable(struct s3c_fb *sfb, int enable) | ||
451 | { | ||
452 | u32 vidcon0 = readl(sfb->regs + VIDCON0); | ||
453 | |||
454 | if (enable && !sfb->output_on) | ||
455 | pm_runtime_get_sync(sfb->dev); | ||
456 | |||
457 | if (enable) { | ||
458 | vidcon0 |= VIDCON0_ENVID | VIDCON0_ENVID_F; | ||
459 | } else { | ||
460 | /* see the note in the framebuffer datasheet about | ||
461 | * why you cannot take both of these bits down at the | ||
462 | * same time. */ | ||
463 | |||
464 | if (vidcon0 & VIDCON0_ENVID) { | ||
465 | vidcon0 |= VIDCON0_ENVID; | ||
466 | vidcon0 &= ~VIDCON0_ENVID_F; | ||
467 | } | ||
468 | } | ||
469 | |||
470 | writel(vidcon0, sfb->regs + VIDCON0); | ||
471 | |||
472 | if (!enable && sfb->output_on) | ||
473 | pm_runtime_put_sync(sfb->dev); | ||
474 | |||
475 | sfb->output_on = enable; | ||
476 | } | ||
477 | |||
478 | /** | ||
444 | * s3c_fb_set_par() - framebuffer request to set new framebuffer state. | 479 | * s3c_fb_set_par() - framebuffer request to set new framebuffer state. |
445 | * @info: The framebuffer to change. | 480 | * @info: The framebuffer to change. |
446 | * | 481 | * |
@@ -461,6 +496,8 @@ static int s3c_fb_set_par(struct fb_info *info) | |||
461 | 496 | ||
462 | dev_dbg(sfb->dev, "setting framebuffer parameters\n"); | 497 | dev_dbg(sfb->dev, "setting framebuffer parameters\n"); |
463 | 498 | ||
499 | pm_runtime_get_sync(sfb->dev); | ||
500 | |||
464 | shadow_protect_win(win, 1); | 501 | shadow_protect_win(win, 1); |
465 | 502 | ||
466 | switch (var->bits_per_pixel) { | 503 | switch (var->bits_per_pixel) { |
@@ -510,9 +547,10 @@ static int s3c_fb_set_par(struct fb_info *info) | |||
510 | if (sfb->variant.is_2443) | 547 | if (sfb->variant.is_2443) |
511 | data |= (1 << 5); | 548 | data |= (1 << 5); |
512 | 549 | ||
513 | data |= VIDCON0_ENVID | VIDCON0_ENVID_F; | ||
514 | writel(data, regs + VIDCON0); | 550 | writel(data, regs + VIDCON0); |
515 | 551 | ||
552 | s3c_fb_enable(sfb, 1); | ||
553 | |||
516 | data = VIDTCON0_VBPD(var->upper_margin - 1) | | 554 | data = VIDTCON0_VBPD(var->upper_margin - 1) | |
517 | VIDTCON0_VFPD(var->lower_margin - 1) | | 555 | VIDTCON0_VFPD(var->lower_margin - 1) | |
518 | VIDTCON0_VSPW(var->vsync_len - 1); | 556 | VIDTCON0_VSPW(var->vsync_len - 1); |
@@ -574,6 +612,7 @@ static int s3c_fb_set_par(struct fb_info *info) | |||
574 | } | 612 | } |
575 | 613 | ||
576 | data = WINCONx_ENWIN; | 614 | data = WINCONx_ENWIN; |
615 | sfb->enabled |= (1 << win->index); | ||
577 | 616 | ||
578 | /* note, since we have to round up the bits-per-pixel, we end up | 617 | /* note, since we have to round up the bits-per-pixel, we end up |
579 | * relying on the bitfield information for r/g/b/a to work out | 618 | * relying on the bitfield information for r/g/b/a to work out |
@@ -621,7 +660,8 @@ static int s3c_fb_set_par(struct fb_info *info) | |||
621 | } else if (var->transp.length == 1) | 660 | } else if (var->transp.length == 1) |
622 | data |= WINCON1_BPPMODE_25BPP_A1888 | 661 | data |= WINCON1_BPPMODE_25BPP_A1888 |
623 | | WINCON1_BLD_PIX; | 662 | | WINCON1_BLD_PIX; |
624 | else if (var->transp.length == 4) | 663 | else if ((var->transp.length == 4) || |
664 | (var->transp.length == 8)) | ||
625 | data |= WINCON1_BPPMODE_28BPP_A4888 | 665 | data |= WINCON1_BPPMODE_28BPP_A4888 |
626 | | WINCON1_BLD_PIX | WINCON1_ALPHA_SEL; | 666 | | WINCON1_BLD_PIX | WINCON1_ALPHA_SEL; |
627 | else | 667 | else |
@@ -654,6 +694,8 @@ static int s3c_fb_set_par(struct fb_info *info) | |||
654 | 694 | ||
655 | shadow_protect_win(win, 0); | 695 | shadow_protect_win(win, 0); |
656 | 696 | ||
697 | pm_runtime_put_sync(sfb->dev); | ||
698 | |||
657 | return 0; | 699 | return 0; |
658 | } | 700 | } |
659 | 701 | ||
@@ -725,6 +767,8 @@ static int s3c_fb_setcolreg(unsigned regno, | |||
725 | dev_dbg(sfb->dev, "%s: win %d: %d => rgb=%d/%d/%d\n", | 767 | dev_dbg(sfb->dev, "%s: win %d: %d => rgb=%d/%d/%d\n", |
726 | __func__, win->index, regno, red, green, blue); | 768 | __func__, win->index, regno, red, green, blue); |
727 | 769 | ||
770 | pm_runtime_get_sync(sfb->dev); | ||
771 | |||
728 | switch (info->fix.visual) { | 772 | switch (info->fix.visual) { |
729 | case FB_VISUAL_TRUECOLOR: | 773 | case FB_VISUAL_TRUECOLOR: |
730 | /* true-colour, use pseudo-palette */ | 774 | /* true-colour, use pseudo-palette */ |
@@ -752,39 +796,15 @@ static int s3c_fb_setcolreg(unsigned regno, | |||
752 | break; | 796 | break; |
753 | 797 | ||
754 | default: | 798 | default: |
799 | pm_runtime_put_sync(sfb->dev); | ||
755 | return 1; /* unknown type */ | 800 | return 1; /* unknown type */ |
756 | } | 801 | } |
757 | 802 | ||
803 | pm_runtime_put_sync(sfb->dev); | ||
758 | return 0; | 804 | return 0; |
759 | } | 805 | } |
760 | 806 | ||
761 | /** | 807 | /** |
762 | * s3c_fb_enable() - Set the state of the main LCD output | ||
763 | * @sfb: The main framebuffer state. | ||
764 | * @enable: The state to set. | ||
765 | */ | ||
766 | static void s3c_fb_enable(struct s3c_fb *sfb, int enable) | ||
767 | { | ||
768 | u32 vidcon0 = readl(sfb->regs + VIDCON0); | ||
769 | |||
770 | if (enable) | ||
771 | vidcon0 |= VIDCON0_ENVID | VIDCON0_ENVID_F; | ||
772 | else { | ||
773 | /* see the note in the framebuffer datasheet about | ||
774 | * why you cannot take both of these bits down at the | ||
775 | * same time. */ | ||
776 | |||
777 | if (!(vidcon0 & VIDCON0_ENVID)) | ||
778 | return; | ||
779 | |||
780 | vidcon0 |= VIDCON0_ENVID; | ||
781 | vidcon0 &= ~VIDCON0_ENVID_F; | ||
782 | } | ||
783 | |||
784 | writel(vidcon0, sfb->regs + VIDCON0); | ||
785 | } | ||
786 | |||
787 | /** | ||
788 | * s3c_fb_blank() - blank or unblank the given window | 808 | * s3c_fb_blank() - blank or unblank the given window |
789 | * @blank_mode: The blank state from FB_BLANK_* | 809 | * @blank_mode: The blank state from FB_BLANK_* |
790 | * @info: The framebuffer to blank. | 810 | * @info: The framebuffer to blank. |
@@ -800,6 +820,8 @@ static int s3c_fb_blank(int blank_mode, struct fb_info *info) | |||
800 | 820 | ||
801 | dev_dbg(sfb->dev, "blank mode %d\n", blank_mode); | 821 | dev_dbg(sfb->dev, "blank mode %d\n", blank_mode); |
802 | 822 | ||
823 | pm_runtime_get_sync(sfb->dev); | ||
824 | |||
803 | wincon = readl(sfb->regs + sfb->variant.wincon + (index * 4)); | 825 | wincon = readl(sfb->regs + sfb->variant.wincon + (index * 4)); |
804 | 826 | ||
805 | switch (blank_mode) { | 827 | switch (blank_mode) { |
@@ -810,12 +832,16 @@ static int s3c_fb_blank(int blank_mode, struct fb_info *info) | |||
810 | 832 | ||
811 | case FB_BLANK_NORMAL: | 833 | case FB_BLANK_NORMAL: |
812 | /* disable the DMA and display 0x0 (black) */ | 834 | /* disable the DMA and display 0x0 (black) */ |
835 | shadow_protect_win(win, 1); | ||
813 | writel(WINxMAP_MAP | WINxMAP_MAP_COLOUR(0x0), | 836 | writel(WINxMAP_MAP | WINxMAP_MAP_COLOUR(0x0), |
814 | sfb->regs + sfb->variant.winmap + (index * 4)); | 837 | sfb->regs + sfb->variant.winmap + (index * 4)); |
838 | shadow_protect_win(win, 0); | ||
815 | break; | 839 | break; |
816 | 840 | ||
817 | case FB_BLANK_UNBLANK: | 841 | case FB_BLANK_UNBLANK: |
842 | shadow_protect_win(win, 1); | ||
818 | writel(0x0, sfb->regs + sfb->variant.winmap + (index * 4)); | 843 | writel(0x0, sfb->regs + sfb->variant.winmap + (index * 4)); |
844 | shadow_protect_win(win, 0); | ||
819 | wincon |= WINCONx_ENWIN; | 845 | wincon |= WINCONx_ENWIN; |
820 | sfb->enabled |= (1 << index); | 846 | sfb->enabled |= (1 << index); |
821 | break; | 847 | break; |
@@ -823,10 +849,13 @@ static int s3c_fb_blank(int blank_mode, struct fb_info *info) | |||
823 | case FB_BLANK_VSYNC_SUSPEND: | 849 | case FB_BLANK_VSYNC_SUSPEND: |
824 | case FB_BLANK_HSYNC_SUSPEND: | 850 | case FB_BLANK_HSYNC_SUSPEND: |
825 | default: | 851 | default: |
852 | pm_runtime_put_sync(sfb->dev); | ||
826 | return 1; | 853 | return 1; |
827 | } | 854 | } |
828 | 855 | ||
856 | shadow_protect_win(win, 1); | ||
829 | writel(wincon, sfb->regs + sfb->variant.wincon + (index * 4)); | 857 | writel(wincon, sfb->regs + sfb->variant.wincon + (index * 4)); |
858 | shadow_protect_win(win, 0); | ||
830 | 859 | ||
831 | /* Check the enabled state to see if we need to be running the | 860 | /* Check the enabled state to see if we need to be running the |
832 | * main LCD interface, as if there are no active windows then | 861 | * main LCD interface, as if there are no active windows then |
@@ -845,8 +874,13 @@ static int s3c_fb_blank(int blank_mode, struct fb_info *info) | |||
845 | /* we're stuck with this until we can do something about overriding | 874 | /* we're stuck with this until we can do something about overriding |
846 | * the power control using the blanking event for a single fb. | 875 | * the power control using the blanking event for a single fb. |
847 | */ | 876 | */ |
848 | if (index == sfb->pdata->default_win) | 877 | if (index == sfb->pdata->default_win) { |
878 | shadow_protect_win(win, 1); | ||
849 | s3c_fb_enable(sfb, blank_mode != FB_BLANK_POWERDOWN ? 1 : 0); | 879 | s3c_fb_enable(sfb, blank_mode != FB_BLANK_POWERDOWN ? 1 : 0); |
880 | shadow_protect_win(win, 0); | ||
881 | } | ||
882 | |||
883 | pm_runtime_put_sync(sfb->dev); | ||
850 | 884 | ||
851 | return 0; | 885 | return 0; |
852 | } | 886 | } |
@@ -870,6 +904,8 @@ static int s3c_fb_pan_display(struct fb_var_screeninfo *var, | |||
870 | void __iomem *buf = sfb->regs + win->index * 8; | 904 | void __iomem *buf = sfb->regs + win->index * 8; |
871 | unsigned int start_boff, end_boff; | 905 | unsigned int start_boff, end_boff; |
872 | 906 | ||
907 | pm_runtime_get_sync(sfb->dev); | ||
908 | |||
873 | /* Offset in bytes to the start of the displayed area */ | 909 | /* Offset in bytes to the start of the displayed area */ |
874 | start_boff = var->yoffset * info->fix.line_length; | 910 | start_boff = var->yoffset * info->fix.line_length; |
875 | /* X offset depends on the current bpp */ | 911 | /* X offset depends on the current bpp */ |
@@ -888,6 +924,7 @@ static int s3c_fb_pan_display(struct fb_var_screeninfo *var, | |||
888 | break; | 924 | break; |
889 | default: | 925 | default: |
890 | dev_err(sfb->dev, "invalid bpp\n"); | 926 | dev_err(sfb->dev, "invalid bpp\n"); |
927 | pm_runtime_put_sync(sfb->dev); | ||
891 | return -EINVAL; | 928 | return -EINVAL; |
892 | } | 929 | } |
893 | } | 930 | } |
@@ -903,6 +940,7 @@ static int s3c_fb_pan_display(struct fb_var_screeninfo *var, | |||
903 | 940 | ||
904 | shadow_protect_win(win, 0); | 941 | shadow_protect_win(win, 0); |
905 | 942 | ||
943 | pm_runtime_put_sync(sfb->dev); | ||
906 | return 0; | 944 | return 0; |
907 | } | 945 | } |
908 | 946 | ||
@@ -992,11 +1030,16 @@ static int s3c_fb_wait_for_vsync(struct s3c_fb *sfb, u32 crtc) | |||
992 | if (crtc != 0) | 1030 | if (crtc != 0) |
993 | return -ENODEV; | 1031 | return -ENODEV; |
994 | 1032 | ||
1033 | pm_runtime_get_sync(sfb->dev); | ||
1034 | |||
995 | count = sfb->vsync_info.count; | 1035 | count = sfb->vsync_info.count; |
996 | s3c_fb_enable_irq(sfb); | 1036 | s3c_fb_enable_irq(sfb); |
997 | ret = wait_event_interruptible_timeout(sfb->vsync_info.wait, | 1037 | ret = wait_event_interruptible_timeout(sfb->vsync_info.wait, |
998 | count != sfb->vsync_info.count, | 1038 | count != sfb->vsync_info.count, |
999 | msecs_to_jiffies(VSYNC_TIMEOUT_MSEC)); | 1039 | msecs_to_jiffies(VSYNC_TIMEOUT_MSEC)); |
1040 | |||
1041 | pm_runtime_put_sync(sfb->dev); | ||
1042 | |||
1000 | if (ret == 0) | 1043 | if (ret == 0) |
1001 | return -ETIMEDOUT; | 1044 | return -ETIMEDOUT; |
1002 | 1045 | ||
@@ -1027,30 +1070,8 @@ static int s3c_fb_ioctl(struct fb_info *info, unsigned int cmd, | |||
1027 | return ret; | 1070 | return ret; |
1028 | } | 1071 | } |
1029 | 1072 | ||
1030 | static int s3c_fb_open(struct fb_info *info, int user) | ||
1031 | { | ||
1032 | struct s3c_fb_win *win = info->par; | ||
1033 | struct s3c_fb *sfb = win->parent; | ||
1034 | |||
1035 | pm_runtime_get_sync(sfb->dev); | ||
1036 | |||
1037 | return 0; | ||
1038 | } | ||
1039 | |||
1040 | static int s3c_fb_release(struct fb_info *info, int user) | ||
1041 | { | ||
1042 | struct s3c_fb_win *win = info->par; | ||
1043 | struct s3c_fb *sfb = win->parent; | ||
1044 | |||
1045 | pm_runtime_put_sync(sfb->dev); | ||
1046 | |||
1047 | return 0; | ||
1048 | } | ||
1049 | |||
1050 | static struct fb_ops s3c_fb_ops = { | 1073 | static struct fb_ops s3c_fb_ops = { |
1051 | .owner = THIS_MODULE, | 1074 | .owner = THIS_MODULE, |
1052 | .fb_open = s3c_fb_open, | ||
1053 | .fb_release = s3c_fb_release, | ||
1054 | .fb_check_var = s3c_fb_check_var, | 1075 | .fb_check_var = s3c_fb_check_var, |
1055 | .fb_set_par = s3c_fb_set_par, | 1076 | .fb_set_par = s3c_fb_set_par, |
1056 | .fb_blank = s3c_fb_blank, | 1077 | .fb_blank = s3c_fb_blank, |
@@ -1452,7 +1473,7 @@ static int __devinit s3c_fb_probe(struct platform_device *pdev) | |||
1452 | dev_err(dev, "failed to create window %d\n", win); | 1473 | dev_err(dev, "failed to create window %d\n", win); |
1453 | for (; win >= 0; win--) | 1474 | for (; win >= 0; win--) |
1454 | s3c_fb_release_win(sfb, sfb->windows[win]); | 1475 | s3c_fb_release_win(sfb, sfb->windows[win]); |
1455 | goto err_irq; | 1476 | goto err_pm_runtime; |
1456 | } | 1477 | } |
1457 | } | 1478 | } |
1458 | 1479 | ||
@@ -1461,7 +1482,8 @@ static int __devinit s3c_fb_probe(struct platform_device *pdev) | |||
1461 | 1482 | ||
1462 | return 0; | 1483 | return 0; |
1463 | 1484 | ||
1464 | err_irq: | 1485 | err_pm_runtime: |
1486 | pm_runtime_put_sync(sfb->dev); | ||
1465 | free_irq(sfb->irq_no, sfb); | 1487 | free_irq(sfb->irq_no, sfb); |
1466 | 1488 | ||
1467 | err_ioremap: | 1489 | err_ioremap: |
@@ -1471,6 +1493,8 @@ err_req_region: | |||
1471 | release_mem_region(sfb->regs_res->start, resource_size(sfb->regs_res)); | 1493 | release_mem_region(sfb->regs_res->start, resource_size(sfb->regs_res)); |
1472 | 1494 | ||
1473 | err_lcd_clk: | 1495 | err_lcd_clk: |
1496 | pm_runtime_disable(sfb->dev); | ||
1497 | |||
1474 | if (!sfb->variant.has_clksel) { | 1498 | if (!sfb->variant.has_clksel) { |
1475 | clk_disable(sfb->lcd_clk); | 1499 | clk_disable(sfb->lcd_clk); |
1476 | clk_put(sfb->lcd_clk); | 1500 | clk_put(sfb->lcd_clk); |
@@ -1524,7 +1548,7 @@ static int __devexit s3c_fb_remove(struct platform_device *pdev) | |||
1524 | return 0; | 1548 | return 0; |
1525 | } | 1549 | } |
1526 | 1550 | ||
1527 | #ifdef CONFIG_PM | 1551 | #ifdef CONFIG_PM_SLEEP |
1528 | static int s3c_fb_suspend(struct device *dev) | 1552 | static int s3c_fb_suspend(struct device *dev) |
1529 | { | 1553 | { |
1530 | struct platform_device *pdev = to_platform_device(dev); | 1554 | struct platform_device *pdev = to_platform_device(dev); |
@@ -1571,10 +1595,15 @@ static int s3c_fb_resume(struct device *dev) | |||
1571 | 1595 | ||
1572 | for (win_no = 0; win_no < sfb->variant.nr_windows - 1; win_no++) { | 1596 | for (win_no = 0; win_no < sfb->variant.nr_windows - 1; win_no++) { |
1573 | void __iomem *regs = sfb->regs + sfb->variant.keycon; | 1597 | void __iomem *regs = sfb->regs + sfb->variant.keycon; |
1598 | win = sfb->windows[win_no]; | ||
1599 | if (!win) | ||
1600 | continue; | ||
1574 | 1601 | ||
1602 | shadow_protect_win(win, 1); | ||
1575 | regs += (win_no * 8); | 1603 | regs += (win_no * 8); |
1576 | writel(0xffffff, regs + WKEYCON0); | 1604 | writel(0xffffff, regs + WKEYCON0); |
1577 | writel(0xffffff, regs + WKEYCON1); | 1605 | writel(0xffffff, regs + WKEYCON1); |
1606 | shadow_protect_win(win, 0); | ||
1578 | } | 1607 | } |
1579 | 1608 | ||
1580 | /* restore framebuffers */ | 1609 | /* restore framebuffers */ |
@@ -1589,27 +1618,19 @@ static int s3c_fb_resume(struct device *dev) | |||
1589 | 1618 | ||
1590 | return 0; | 1619 | return 0; |
1591 | } | 1620 | } |
1621 | #endif | ||
1592 | 1622 | ||
1623 | #ifdef CONFIG_PM_RUNTIME | ||
1593 | static int s3c_fb_runtime_suspend(struct device *dev) | 1624 | static int s3c_fb_runtime_suspend(struct device *dev) |
1594 | { | 1625 | { |
1595 | struct platform_device *pdev = to_platform_device(dev); | 1626 | struct platform_device *pdev = to_platform_device(dev); |
1596 | struct s3c_fb *sfb = platform_get_drvdata(pdev); | 1627 | struct s3c_fb *sfb = platform_get_drvdata(pdev); |
1597 | struct s3c_fb_win *win; | ||
1598 | int win_no; | ||
1599 | |||
1600 | for (win_no = S3C_FB_MAX_WIN - 1; win_no >= 0; win_no--) { | ||
1601 | win = sfb->windows[win_no]; | ||
1602 | if (!win) | ||
1603 | continue; | ||
1604 | |||
1605 | /* use the blank function to push into power-down */ | ||
1606 | s3c_fb_blank(FB_BLANK_POWERDOWN, win->fbinfo); | ||
1607 | } | ||
1608 | 1628 | ||
1609 | if (!sfb->variant.has_clksel) | 1629 | if (!sfb->variant.has_clksel) |
1610 | clk_disable(sfb->lcd_clk); | 1630 | clk_disable(sfb->lcd_clk); |
1611 | 1631 | ||
1612 | clk_disable(sfb->bus_clk); | 1632 | clk_disable(sfb->bus_clk); |
1633 | |||
1613 | return 0; | 1634 | return 0; |
1614 | } | 1635 | } |
1615 | 1636 | ||
@@ -1618,8 +1639,6 @@ static int s3c_fb_runtime_resume(struct device *dev) | |||
1618 | struct platform_device *pdev = to_platform_device(dev); | 1639 | struct platform_device *pdev = to_platform_device(dev); |
1619 | struct s3c_fb *sfb = platform_get_drvdata(pdev); | 1640 | struct s3c_fb *sfb = platform_get_drvdata(pdev); |
1620 | struct s3c_fb_platdata *pd = sfb->pdata; | 1641 | struct s3c_fb_platdata *pd = sfb->pdata; |
1621 | struct s3c_fb_win *win; | ||
1622 | int win_no; | ||
1623 | 1642 | ||
1624 | clk_enable(sfb->bus_clk); | 1643 | clk_enable(sfb->bus_clk); |
1625 | 1644 | ||
@@ -1630,39 +1649,10 @@ static int s3c_fb_runtime_resume(struct device *dev) | |||
1630 | pd->setup_gpio(); | 1649 | pd->setup_gpio(); |
1631 | writel(pd->vidcon1, sfb->regs + VIDCON1); | 1650 | writel(pd->vidcon1, sfb->regs + VIDCON1); |
1632 | 1651 | ||
1633 | /* zero all windows before we do anything */ | ||
1634 | for (win_no = 0; win_no < sfb->variant.nr_windows; win_no++) | ||
1635 | s3c_fb_clear_win(sfb, win_no); | ||
1636 | |||
1637 | for (win_no = 0; win_no < sfb->variant.nr_windows - 1; win_no++) { | ||
1638 | void __iomem *regs = sfb->regs + sfb->variant.keycon; | ||
1639 | |||
1640 | regs += (win_no * 8); | ||
1641 | writel(0xffffff, regs + WKEYCON0); | ||
1642 | writel(0xffffff, regs + WKEYCON1); | ||
1643 | } | ||
1644 | |||
1645 | /* restore framebuffers */ | ||
1646 | for (win_no = 0; win_no < S3C_FB_MAX_WIN; win_no++) { | ||
1647 | win = sfb->windows[win_no]; | ||
1648 | if (!win) | ||
1649 | continue; | ||
1650 | |||
1651 | dev_dbg(&pdev->dev, "resuming window %d\n", win_no); | ||
1652 | s3c_fb_set_par(win->fbinfo); | ||
1653 | } | ||
1654 | |||
1655 | return 0; | 1652 | return 0; |
1656 | } | 1653 | } |
1657 | |||
1658 | #else | ||
1659 | #define s3c_fb_suspend NULL | ||
1660 | #define s3c_fb_resume NULL | ||
1661 | #define s3c_fb_runtime_suspend NULL | ||
1662 | #define s3c_fb_runtime_resume NULL | ||
1663 | #endif | 1654 | #endif |
1664 | 1655 | ||
1665 | |||
1666 | #define VALID_BPP124 (VALID_BPP(1) | VALID_BPP(2) | VALID_BPP(4)) | 1656 | #define VALID_BPP124 (VALID_BPP(1) | VALID_BPP(2) | VALID_BPP(4)) |
1667 | #define VALID_BPP1248 (VALID_BPP124 | VALID_BPP(8)) | 1657 | #define VALID_BPP1248 (VALID_BPP124 | VALID_BPP(8)) |
1668 | 1658 | ||
@@ -1985,10 +1975,9 @@ static struct platform_device_id s3c_fb_driver_ids[] = { | |||
1985 | MODULE_DEVICE_TABLE(platform, s3c_fb_driver_ids); | 1975 | MODULE_DEVICE_TABLE(platform, s3c_fb_driver_ids); |
1986 | 1976 | ||
1987 | static const struct dev_pm_ops s3cfb_pm_ops = { | 1977 | static const struct dev_pm_ops s3cfb_pm_ops = { |
1988 | .suspend = s3c_fb_suspend, | 1978 | SET_SYSTEM_SLEEP_PM_OPS(s3c_fb_suspend, s3c_fb_resume) |
1989 | .resume = s3c_fb_resume, | 1979 | SET_RUNTIME_PM_OPS(s3c_fb_runtime_suspend, s3c_fb_runtime_resume, |
1990 | .runtime_suspend = s3c_fb_runtime_suspend, | 1980 | NULL) |
1991 | .runtime_resume = s3c_fb_runtime_resume, | ||
1992 | }; | 1981 | }; |
1993 | 1982 | ||
1994 | static struct platform_driver s3c_fb_driver = { | 1983 | static struct platform_driver s3c_fb_driver = { |
@@ -2002,18 +1991,7 @@ static struct platform_driver s3c_fb_driver = { | |||
2002 | }, | 1991 | }, |
2003 | }; | 1992 | }; |
2004 | 1993 | ||
2005 | static int __init s3c_fb_init(void) | 1994 | module_platform_driver(s3c_fb_driver); |
2006 | { | ||
2007 | return platform_driver_register(&s3c_fb_driver); | ||
2008 | } | ||
2009 | |||
2010 | static void __exit s3c_fb_cleanup(void) | ||
2011 | { | ||
2012 | platform_driver_unregister(&s3c_fb_driver); | ||
2013 | } | ||
2014 | |||
2015 | module_init(s3c_fb_init); | ||
2016 | module_exit(s3c_fb_cleanup); | ||
2017 | 1995 | ||
2018 | MODULE_AUTHOR("Ben Dooks <ben@simtec.co.uk>"); | 1996 | MODULE_AUTHOR("Ben Dooks <ben@simtec.co.uk>"); |
2019 | MODULE_DESCRIPTION("Samsung S3C SoC Framebuffer driver"); | 1997 | MODULE_DESCRIPTION("Samsung S3C SoC Framebuffer driver"); |
diff --git a/drivers/video/s3c2410fb.c b/drivers/video/s3c2410fb.c index ee4c0df217f7..77f34c614c86 100644 --- a/drivers/video/s3c2410fb.c +++ b/drivers/video/s3c2410fb.c | |||
@@ -26,8 +26,8 @@ | |||
26 | #include <linux/platform_device.h> | 26 | #include <linux/platform_device.h> |
27 | #include <linux/clk.h> | 27 | #include <linux/clk.h> |
28 | #include <linux/cpufreq.h> | 28 | #include <linux/cpufreq.h> |
29 | #include <linux/io.h> | ||
29 | 30 | ||
30 | #include <asm/io.h> | ||
31 | #include <asm/div64.h> | 31 | #include <asm/div64.h> |
32 | 32 | ||
33 | #include <asm/mach/map.h> | 33 | #include <asm/mach/map.h> |
@@ -45,10 +45,10 @@ | |||
45 | #ifdef CONFIG_FB_S3C2410_DEBUG | 45 | #ifdef CONFIG_FB_S3C2410_DEBUG |
46 | static int debug = 1; | 46 | static int debug = 1; |
47 | #else | 47 | #else |
48 | static int debug = 0; | 48 | static int debug; |
49 | #endif | 49 | #endif |
50 | 50 | ||
51 | #define dprintk(msg...) if (debug) { printk(KERN_DEBUG "s3c2410fb: " msg); } | 51 | #define dprintk(msg...) if (debug) printk(KERN_DEBUG "s3c2410fb: " msg); |
52 | 52 | ||
53 | /* useful functions */ | 53 | /* useful functions */ |
54 | 54 | ||
@@ -567,11 +567,10 @@ static int s3c2410fb_blank(int blank_mode, struct fb_info *info) | |||
567 | 567 | ||
568 | tpal_reg += is_s3c2412(fbi) ? S3C2412_TPAL : S3C2410_TPAL; | 568 | tpal_reg += is_s3c2412(fbi) ? S3C2412_TPAL : S3C2410_TPAL; |
569 | 569 | ||
570 | if (blank_mode == FB_BLANK_POWERDOWN) { | 570 | if (blank_mode == FB_BLANK_POWERDOWN) |
571 | s3c2410fb_lcd_enable(fbi, 0); | 571 | s3c2410fb_lcd_enable(fbi, 0); |
572 | } else { | 572 | else |
573 | s3c2410fb_lcd_enable(fbi, 1); | 573 | s3c2410fb_lcd_enable(fbi, 1); |
574 | } | ||
575 | 574 | ||
576 | if (blank_mode == FB_BLANK_UNBLANK) | 575 | if (blank_mode == FB_BLANK_UNBLANK) |
577 | writel(0x0, tpal_reg); | 576 | writel(0x0, tpal_reg); |
@@ -812,7 +811,7 @@ static inline void s3c2410fb_cpufreq_deregister(struct s3c2410fb_info *info) | |||
812 | #endif | 811 | #endif |
813 | 812 | ||
814 | 813 | ||
815 | static char driver_name[] = "s3c2410fb"; | 814 | static const char driver_name[] = "s3c2410fb"; |
816 | 815 | ||
817 | static int __devinit s3c24xxfb_probe(struct platform_device *pdev, | 816 | static int __devinit s3c24xxfb_probe(struct platform_device *pdev, |
818 | enum s3c_drv_type drv_type) | 817 | enum s3c_drv_type drv_type) |
@@ -881,7 +880,10 @@ static int __devinit s3c24xxfb_probe(struct platform_device *pdev, | |||
881 | goto release_mem; | 880 | goto release_mem; |
882 | } | 881 | } |
883 | 882 | ||
884 | info->irq_base = info->io + ((drv_type == DRV_S3C2412) ? S3C2412_LCDINTBASE : S3C2410_LCDINTBASE); | 883 | if (drv_type == DRV_S3C2412) |
884 | info->irq_base = info->io + S3C2412_LCDINTBASE; | ||
885 | else | ||
886 | info->irq_base = info->io + S3C2410_LCDINTBASE; | ||
885 | 887 | ||
886 | dprintk("devinit\n"); | 888 | dprintk("devinit\n"); |
887 | 889 | ||
@@ -927,7 +929,7 @@ static int __devinit s3c24xxfb_probe(struct platform_device *pdev, | |||
927 | clk_enable(info->clk); | 929 | clk_enable(info->clk); |
928 | dprintk("got and enabled clock\n"); | 930 | dprintk("got and enabled clock\n"); |
929 | 931 | ||
930 | msleep(1); | 932 | usleep_range(1000, 1000); |
931 | 933 | ||
932 | info->clk_rate = clk_get_rate(info->clk); | 934 | info->clk_rate = clk_get_rate(info->clk); |
933 | 935 | ||
@@ -975,9 +977,8 @@ static int __devinit s3c24xxfb_probe(struct platform_device *pdev, | |||
975 | 977 | ||
976 | /* create device files */ | 978 | /* create device files */ |
977 | ret = device_create_file(&pdev->dev, &dev_attr_debug); | 979 | ret = device_create_file(&pdev->dev, &dev_attr_debug); |
978 | if (ret) { | 980 | if (ret) |
979 | printk(KERN_ERR "failed to add debug attribute\n"); | 981 | printk(KERN_ERR "failed to add debug attribute\n"); |
980 | } | ||
981 | 982 | ||
982 | printk(KERN_INFO "fb%d: %s frame buffer device\n", | 983 | printk(KERN_INFO "fb%d: %s frame buffer device\n", |
983 | fbinfo->node, fbinfo->fix.id); | 984 | fbinfo->node, fbinfo->fix.id); |
@@ -1027,7 +1028,7 @@ static int __devexit s3c2410fb_remove(struct platform_device *pdev) | |||
1027 | s3c2410fb_cpufreq_deregister(info); | 1028 | s3c2410fb_cpufreq_deregister(info); |
1028 | 1029 | ||
1029 | s3c2410fb_lcd_enable(info, 0); | 1030 | s3c2410fb_lcd_enable(info, 0); |
1030 | msleep(1); | 1031 | usleep_range(1000, 1000); |
1031 | 1032 | ||
1032 | s3c2410fb_unmap_video_memory(fbinfo); | 1033 | s3c2410fb_unmap_video_memory(fbinfo); |
1033 | 1034 | ||
@@ -1064,7 +1065,7 @@ static int s3c2410fb_suspend(struct platform_device *dev, pm_message_t state) | |||
1064 | * the LCD DMA engine is not going to get back on the bus | 1065 | * the LCD DMA engine is not going to get back on the bus |
1065 | * before the clock goes off again (bjd) */ | 1066 | * before the clock goes off again (bjd) */ |
1066 | 1067 | ||
1067 | msleep(1); | 1068 | usleep_range(1000, 1000); |
1068 | clk_disable(info->clk); | 1069 | clk_disable(info->clk); |
1069 | 1070 | ||
1070 | return 0; | 1071 | return 0; |
@@ -1076,7 +1077,7 @@ static int s3c2410fb_resume(struct platform_device *dev) | |||
1076 | struct s3c2410fb_info *info = fbinfo->par; | 1077 | struct s3c2410fb_info *info = fbinfo->par; |
1077 | 1078 | ||
1078 | clk_enable(info->clk); | 1079 | clk_enable(info->clk); |
1079 | msleep(1); | 1080 | usleep_range(1000, 1000); |
1080 | 1081 | ||
1081 | s3c2410fb_init_registers(fbinfo); | 1082 | s3c2410fb_init_registers(fbinfo); |
1082 | 1083 | ||
diff --git a/drivers/video/s3fb.c b/drivers/video/s3fb.c index 946a949f4c7d..2c80246b18b8 100644 --- a/drivers/video/s3fb.c +++ b/drivers/video/s3fb.c | |||
@@ -727,7 +727,7 @@ static int s3fb_set_par(struct fb_info *info) | |||
727 | if (par->chip == CHIP_988_VIRGE_VX) { | 727 | if (par->chip == CHIP_988_VIRGE_VX) { |
728 | vga_wcrt(par->state.vgabase, 0x50, 0x00); | 728 | vga_wcrt(par->state.vgabase, 0x50, 0x00); |
729 | vga_wcrt(par->state.vgabase, 0x67, 0x50); | 729 | vga_wcrt(par->state.vgabase, 0x67, 0x50); |
730 | 730 | msleep(10); /* screen remains blank sometimes without this */ | |
731 | vga_wcrt(par->state.vgabase, 0x63, (mode <= 2) ? 0x90 : 0x09); | 731 | vga_wcrt(par->state.vgabase, 0x63, (mode <= 2) ? 0x90 : 0x09); |
732 | vga_wcrt(par->state.vgabase, 0x66, 0x90); | 732 | vga_wcrt(par->state.vgabase, 0x66, 0x90); |
733 | } | 733 | } |
@@ -901,7 +901,8 @@ static int s3fb_set_par(struct fb_info *info) | |||
901 | 901 | ||
902 | /* Set Data Transfer Position */ | 902 | /* Set Data Transfer Position */ |
903 | hsstart = ((info->var.xres + info->var.right_margin) * hmul) / 8; | 903 | hsstart = ((info->var.xres + info->var.right_margin) * hmul) / 8; |
904 | value = clamp((htotal + hsstart + 1) / 2, hsstart + 4, htotal + 1); | 904 | /* + 2 is needed for Virge/VX, does no harm on other cards */ |
905 | value = clamp((htotal + hsstart + 1) / 2 + 2, hsstart + 4, htotal + 1); | ||
905 | svga_wcrt_multi(par->state.vgabase, s3_dtpc_regs, value); | 906 | svga_wcrt_multi(par->state.vgabase, s3_dtpc_regs, value); |
906 | 907 | ||
907 | memset_io(info->screen_base, 0x00, screen_size); | 908 | memset_io(info->screen_base, 0x00, screen_size); |
@@ -1216,6 +1217,31 @@ static int __devinit s3_pci_probe(struct pci_dev *dev, const struct pci_device_i | |||
1216 | info->screen_size = 2 << 20; | 1217 | info->screen_size = 2 << 20; |
1217 | break; | 1218 | break; |
1218 | } | 1219 | } |
1220 | } else if (par->chip == CHIP_988_VIRGE_VX) { | ||
1221 | switch ((regval & 0x60) >> 5) { | ||
1222 | case 0: /* 2MB */ | ||
1223 | info->screen_size = 2 << 20; | ||
1224 | break; | ||
1225 | case 1: /* 4MB */ | ||
1226 | info->screen_size = 4 << 20; | ||
1227 | break; | ||
1228 | case 2: /* 6MB */ | ||
1229 | info->screen_size = 6 << 20; | ||
1230 | break; | ||
1231 | case 3: /* 8MB */ | ||
1232 | info->screen_size = 8 << 20; | ||
1233 | break; | ||
1234 | } | ||
1235 | /* off-screen memory */ | ||
1236 | regval = vga_rcrt(par->state.vgabase, 0x37); | ||
1237 | switch ((regval & 0x60) >> 5) { | ||
1238 | case 1: /* 4MB */ | ||
1239 | info->screen_size -= 4 << 20; | ||
1240 | break; | ||
1241 | case 2: /* 2MB */ | ||
1242 | info->screen_size -= 2 << 20; | ||
1243 | break; | ||
1244 | } | ||
1219 | } else | 1245 | } else |
1220 | info->screen_size = s3_memsizes[regval >> 5] << 10; | 1246 | info->screen_size = s3_memsizes[regval >> 5] << 10; |
1221 | info->fix.smem_len = info->screen_size; | 1247 | info->fix.smem_len = info->screen_size; |
diff --git a/drivers/video/sbuslib.c b/drivers/video/sbuslib.c index 37d764ad56b0..3c1de981a18c 100644 --- a/drivers/video/sbuslib.c +++ b/drivers/video/sbuslib.c | |||
@@ -76,7 +76,7 @@ int sbusfb_mmap_helper(struct sbus_mmap_map *map, | |||
76 | map_offset = (physbase + map[i].poff) & POFF_MASK; | 76 | map_offset = (physbase + map[i].poff) & POFF_MASK; |
77 | break; | 77 | break; |
78 | } | 78 | } |
79 | if (!map_size){ | 79 | if (!map_size) { |
80 | page += PAGE_SIZE; | 80 | page += PAGE_SIZE; |
81 | continue; | 81 | continue; |
82 | } | 82 | } |
diff --git a/drivers/video/sh7760fb.c b/drivers/video/sh7760fb.c index 45e47d847163..83b16e237a0e 100644 --- a/drivers/video/sh7760fb.c +++ b/drivers/video/sh7760fb.c | |||
@@ -585,18 +585,7 @@ static struct platform_driver sh7760_lcdc_driver = { | |||
585 | .remove = __devexit_p(sh7760fb_remove), | 585 | .remove = __devexit_p(sh7760fb_remove), |
586 | }; | 586 | }; |
587 | 587 | ||
588 | static int __init sh7760fb_init(void) | 588 | module_platform_driver(sh7760_lcdc_driver); |
589 | { | ||
590 | return platform_driver_register(&sh7760_lcdc_driver); | ||
591 | } | ||
592 | |||
593 | static void __exit sh7760fb_exit(void) | ||
594 | { | ||
595 | platform_driver_unregister(&sh7760_lcdc_driver); | ||
596 | } | ||
597 | |||
598 | module_init(sh7760fb_init); | ||
599 | module_exit(sh7760fb_exit); | ||
600 | 589 | ||
601 | MODULE_AUTHOR("Nobuhiro Iwamatsu, Manuel Lauss"); | 590 | MODULE_AUTHOR("Nobuhiro Iwamatsu, Manuel Lauss"); |
602 | MODULE_DESCRIPTION("FBdev for SH7760/63 integrated LCD Controller"); | 591 | MODULE_DESCRIPTION("FBdev for SH7760/63 integrated LCD Controller"); |
diff --git a/drivers/video/sh_mipi_dsi.c b/drivers/video/sh_mipi_dsi.c index 72ee96bc6b3e..05151b82f40f 100644 --- a/drivers/video/sh_mipi_dsi.c +++ b/drivers/video/sh_mipi_dsi.c | |||
@@ -8,6 +8,7 @@ | |||
8 | * published by the Free Software Foundation. | 8 | * published by the Free Software Foundation. |
9 | */ | 9 | */ |
10 | 10 | ||
11 | #include <linux/bitmap.h> | ||
11 | #include <linux/clk.h> | 12 | #include <linux/clk.h> |
12 | #include <linux/delay.h> | 13 | #include <linux/delay.h> |
13 | #include <linux/init.h> | 14 | #include <linux/init.h> |
@@ -41,6 +42,7 @@ | |||
41 | #define VMCTR1 0x0020 | 42 | #define VMCTR1 0x0020 |
42 | #define VMCTR2 0x0024 | 43 | #define VMCTR2 0x0024 |
43 | #define VMLEN1 0x0028 | 44 | #define VMLEN1 0x0028 |
45 | #define VMLEN2 0x002c | ||
44 | #define CMTSRTREQ 0x0070 | 46 | #define CMTSRTREQ 0x0070 |
45 | #define CMTSRTCTR 0x00d0 | 47 | #define CMTSRTCTR 0x00d0 |
46 | 48 | ||
@@ -51,8 +53,7 @@ struct sh_mipi { | |||
51 | void __iomem *base; | 53 | void __iomem *base; |
52 | void __iomem *linkbase; | 54 | void __iomem *linkbase; |
53 | struct clk *dsit_clk; | 55 | struct clk *dsit_clk; |
54 | struct clk *dsip_clk; | 56 | struct platform_device *pdev; |
55 | struct device *dev; | ||
56 | 57 | ||
57 | void *next_board_data; | 58 | void *next_board_data; |
58 | void (*next_display_on)(void *board_data, struct fb_info *info); | 59 | void (*next_display_on)(void *board_data, struct fb_info *info); |
@@ -124,35 +125,15 @@ static void sh_mipi_shutdown(struct platform_device *pdev) | |||
124 | sh_mipi_dsi_enable(mipi, false); | 125 | sh_mipi_dsi_enable(mipi, false); |
125 | } | 126 | } |
126 | 127 | ||
127 | static void mipi_display_on(void *arg, struct fb_info *info) | ||
128 | { | ||
129 | struct sh_mipi *mipi = arg; | ||
130 | |||
131 | pm_runtime_get_sync(mipi->dev); | ||
132 | sh_mipi_dsi_enable(mipi, true); | ||
133 | |||
134 | if (mipi->next_display_on) | ||
135 | mipi->next_display_on(mipi->next_board_data, info); | ||
136 | } | ||
137 | |||
138 | static void mipi_display_off(void *arg) | ||
139 | { | ||
140 | struct sh_mipi *mipi = arg; | ||
141 | |||
142 | if (mipi->next_display_off) | ||
143 | mipi->next_display_off(mipi->next_board_data); | ||
144 | |||
145 | sh_mipi_dsi_enable(mipi, false); | ||
146 | pm_runtime_put(mipi->dev); | ||
147 | } | ||
148 | |||
149 | static int __init sh_mipi_setup(struct sh_mipi *mipi, | 128 | static int __init sh_mipi_setup(struct sh_mipi *mipi, |
150 | struct sh_mipi_dsi_info *pdata) | 129 | struct sh_mipi_dsi_info *pdata) |
151 | { | 130 | { |
152 | void __iomem *base = mipi->base; | 131 | void __iomem *base = mipi->base; |
153 | struct sh_mobile_lcdc_chan_cfg *ch = pdata->lcd_chan; | 132 | struct sh_mobile_lcdc_chan_cfg *ch = pdata->lcd_chan; |
154 | u32 pctype, datatype, pixfmt, linelength, vmctr2 = 0x00e00000; | 133 | u32 pctype, datatype, pixfmt, linelength, vmctr2; |
134 | u32 tmp, top, bottom, delay, div; | ||
155 | bool yuv; | 135 | bool yuv; |
136 | int bpp; | ||
156 | 137 | ||
157 | /* | 138 | /* |
158 | * Select data format. MIPI DSI is not hot-pluggable, so, we just use | 139 | * Select data format. MIPI DSI is not hot-pluggable, so, we just use |
@@ -253,6 +234,9 @@ static int __init sh_mipi_setup(struct sh_mipi *mipi, | |||
253 | (!yuv && ch->interface_type != RGB24)) | 234 | (!yuv && ch->interface_type != RGB24)) |
254 | return -EINVAL; | 235 | return -EINVAL; |
255 | 236 | ||
237 | if (!pdata->lane) | ||
238 | return -EINVAL; | ||
239 | |||
256 | /* reset DSI link */ | 240 | /* reset DSI link */ |
257 | iowrite32(0x00000001, base + SYSCTRL); | 241 | iowrite32(0x00000001, base + SYSCTRL); |
258 | /* Hold reset for 100 cycles of the slowest of bus, HS byte and LP clock */ | 242 | /* Hold reset for 100 cycles of the slowest of bus, HS byte and LP clock */ |
@@ -262,15 +246,6 @@ static int __init sh_mipi_setup(struct sh_mipi *mipi, | |||
262 | /* setup DSI link */ | 246 | /* setup DSI link */ |
263 | 247 | ||
264 | /* | 248 | /* |
265 | * Default = ULPS enable | | ||
266 | * Contention detection enabled | | ||
267 | * EoT packet transmission enable | | ||
268 | * CRC check enable | | ||
269 | * ECC check enable | ||
270 | * additionally enable first two lanes | ||
271 | */ | ||
272 | iowrite32(0x00003703, base + SYSCONF); | ||
273 | /* | ||
274 | * T_wakeup = 0x7000 | 249 | * T_wakeup = 0x7000 |
275 | * T_hs-trail = 3 | 250 | * T_hs-trail = 3 |
276 | * T_hs-prepare = 3 | 251 | * T_hs-prepare = 3 |
@@ -290,15 +265,24 @@ static int __init sh_mipi_setup(struct sh_mipi *mipi, | |||
290 | iowrite32(0x0fffffff, base + TATOVSET); | 265 | iowrite32(0x0fffffff, base + TATOVSET); |
291 | /* Peripheral reset timeout, default 0xffffffff */ | 266 | /* Peripheral reset timeout, default 0xffffffff */ |
292 | iowrite32(0x0fffffff, base + PRTOVSET); | 267 | iowrite32(0x0fffffff, base + PRTOVSET); |
293 | /* Enable timeout counters */ | ||
294 | iowrite32(0x00000f00, base + DSICTRL); | ||
295 | /* Interrupts not used, disable all */ | 268 | /* Interrupts not used, disable all */ |
296 | iowrite32(0, base + DSIINTE); | 269 | iowrite32(0, base + DSIINTE); |
297 | /* DSI-Tx bias on */ | 270 | /* DSI-Tx bias on */ |
298 | iowrite32(0x00000001, base + PHYCTRL); | 271 | iowrite32(0x00000001, base + PHYCTRL); |
299 | udelay(200); | 272 | udelay(200); |
300 | /* Deassert resets, power on, set multiplier */ | 273 | /* Deassert resets, power on */ |
301 | iowrite32(0x03070b01, base + PHYCTRL); | 274 | iowrite32(0x03070001, base + PHYCTRL); |
275 | |||
276 | /* | ||
277 | * Default = ULPS enable | | ||
278 | * Contention detection enabled | | ||
279 | * EoT packet transmission enable | | ||
280 | * CRC check enable | | ||
281 | * ECC check enable | ||
282 | */ | ||
283 | bitmap_fill((unsigned long *)&tmp, pdata->lane); | ||
284 | tmp |= 0x00003700; | ||
285 | iowrite32(tmp, base + SYSCONF); | ||
302 | 286 | ||
303 | /* setup l-bridge */ | 287 | /* setup l-bridge */ |
304 | 288 | ||
@@ -316,18 +300,68 @@ static int __init sh_mipi_setup(struct sh_mipi *mipi, | |||
316 | * Non-burst mode with sync pulses: VSE and HSE are output, | 300 | * Non-burst mode with sync pulses: VSE and HSE are output, |
317 | * HSA period allowed, no commands in LP | 301 | * HSA period allowed, no commands in LP |
318 | */ | 302 | */ |
303 | vmctr2 = 0; | ||
304 | if (pdata->flags & SH_MIPI_DSI_VSEE) | ||
305 | vmctr2 |= 1 << 23; | ||
306 | if (pdata->flags & SH_MIPI_DSI_HSEE) | ||
307 | vmctr2 |= 1 << 22; | ||
308 | if (pdata->flags & SH_MIPI_DSI_HSAE) | ||
309 | vmctr2 |= 1 << 21; | ||
310 | if (pdata->flags & SH_MIPI_DSI_BL2E) | ||
311 | vmctr2 |= 1 << 17; | ||
319 | if (pdata->flags & SH_MIPI_DSI_HSABM) | 312 | if (pdata->flags & SH_MIPI_DSI_HSABM) |
320 | vmctr2 |= 0x20; | 313 | vmctr2 |= 1 << 5; |
321 | if (pdata->flags & SH_MIPI_DSI_HSPBM) | 314 | if (pdata->flags & SH_MIPI_DSI_HBPBM) |
322 | vmctr2 |= 0x10; | 315 | vmctr2 |= 1 << 4; |
316 | if (pdata->flags & SH_MIPI_DSI_HFPBM) | ||
317 | vmctr2 |= 1 << 3; | ||
323 | iowrite32(vmctr2, mipi->linkbase + VMCTR2); | 318 | iowrite32(vmctr2, mipi->linkbase + VMCTR2); |
324 | 319 | ||
325 | /* | 320 | /* |
326 | * 0x660 = 1632 bytes per line (RGB24, 544 pixels: see | 321 | * VMLEN1 = RGBLEN | HSALEN |
327 | * sh_mobile_lcdc_info.ch[0].lcd_cfg[0].xres), HSALEN = 1 - default | 322 | * |
328 | * (unused if VMCTR2[HSABM] = 0) | 323 | * see |
324 | * Video mode - Blanking Packet setting | ||
325 | */ | ||
326 | top = linelength << 16; /* RGBLEN */ | ||
327 | bottom = 0x00000001; | ||
328 | if (pdata->flags & SH_MIPI_DSI_HSABM) /* HSALEN */ | ||
329 | bottom = (pdata->lane * ch->lcd_cfg[0].hsync_len) - 10; | ||
330 | iowrite32(top | bottom , mipi->linkbase + VMLEN1); | ||
331 | |||
332 | /* | ||
333 | * VMLEN2 = HBPLEN | HFPLEN | ||
334 | * | ||
335 | * see | ||
336 | * Video mode - Blanking Packet setting | ||
329 | */ | 337 | */ |
330 | iowrite32(1 | (linelength << 16), mipi->linkbase + VMLEN1); | 338 | top = 0x00010000; |
339 | bottom = 0x00000001; | ||
340 | delay = 0; | ||
341 | |||
342 | div = 1; /* HSbyteCLK is calculation base | ||
343 | * HS4divCLK = HSbyteCLK/2 | ||
344 | * HS6divCLK is not supported for now */ | ||
345 | if (pdata->flags & SH_MIPI_DSI_HS4divCLK) | ||
346 | div = 2; | ||
347 | |||
348 | if (pdata->flags & SH_MIPI_DSI_HFPBM) { /* HBPLEN */ | ||
349 | top = ch->lcd_cfg[0].hsync_len + ch->lcd_cfg[0].left_margin; | ||
350 | top = ((pdata->lane * top / div) - 10) << 16; | ||
351 | } | ||
352 | if (pdata->flags & SH_MIPI_DSI_HBPBM) { /* HFPLEN */ | ||
353 | bottom = ch->lcd_cfg[0].right_margin; | ||
354 | bottom = (pdata->lane * bottom / div) - 12; | ||
355 | } | ||
356 | |||
357 | bpp = linelength / ch->lcd_cfg[0].xres; /* byte / pixel */ | ||
358 | if ((pdata->lane / div) > bpp) { | ||
359 | tmp = ch->lcd_cfg[0].xres / bpp; /* output cycle */ | ||
360 | tmp = ch->lcd_cfg[0].xres - tmp; /* (input - output) cycle */ | ||
361 | delay = (pdata->lane * tmp); | ||
362 | } | ||
363 | |||
364 | iowrite32(top | (bottom + delay) , mipi->linkbase + VMLEN2); | ||
331 | 365 | ||
332 | msleep(5); | 366 | msleep(5); |
333 | 367 | ||
@@ -352,9 +386,56 @@ static int __init sh_mipi_setup(struct sh_mipi *mipi, | |||
352 | pixfmt << 4); | 386 | pixfmt << 4); |
353 | sh_mipi_dcs(ch->chan, MIPI_DCS_SET_DISPLAY_ON); | 387 | sh_mipi_dcs(ch->chan, MIPI_DCS_SET_DISPLAY_ON); |
354 | 388 | ||
389 | /* Enable timeout counters */ | ||
390 | iowrite32(0x00000f00, base + DSICTRL); | ||
391 | |||
355 | return 0; | 392 | return 0; |
356 | } | 393 | } |
357 | 394 | ||
395 | static void mipi_display_on(void *arg, struct fb_info *info) | ||
396 | { | ||
397 | struct sh_mipi *mipi = arg; | ||
398 | struct sh_mipi_dsi_info *pdata = mipi->pdev->dev.platform_data; | ||
399 | int ret; | ||
400 | |||
401 | pm_runtime_get_sync(&mipi->pdev->dev); | ||
402 | |||
403 | ret = pdata->set_dot_clock(mipi->pdev, mipi->base, 1); | ||
404 | if (ret < 0) | ||
405 | goto mipi_display_on_fail1; | ||
406 | |||
407 | ret = sh_mipi_setup(mipi, pdata); | ||
408 | if (ret < 0) | ||
409 | goto mipi_display_on_fail2; | ||
410 | |||
411 | sh_mipi_dsi_enable(mipi, true); | ||
412 | |||
413 | if (mipi->next_display_on) | ||
414 | mipi->next_display_on(mipi->next_board_data, info); | ||
415 | |||
416 | return; | ||
417 | |||
418 | mipi_display_on_fail1: | ||
419 | pm_runtime_put_sync(&mipi->pdev->dev); | ||
420 | mipi_display_on_fail2: | ||
421 | pdata->set_dot_clock(mipi->pdev, mipi->base, 0); | ||
422 | } | ||
423 | |||
424 | static void mipi_display_off(void *arg) | ||
425 | { | ||
426 | struct sh_mipi *mipi = arg; | ||
427 | struct sh_mipi_dsi_info *pdata = mipi->pdev->dev.platform_data; | ||
428 | |||
429 | if (mipi->next_display_off) | ||
430 | mipi->next_display_off(mipi->next_board_data); | ||
431 | |||
432 | sh_mipi_dsi_enable(mipi, false); | ||
433 | |||
434 | pdata->set_dot_clock(mipi->pdev, mipi->base, 0); | ||
435 | |||
436 | pm_runtime_put_sync(&mipi->pdev->dev); | ||
437 | } | ||
438 | |||
358 | static int __init sh_mipi_probe(struct platform_device *pdev) | 439 | static int __init sh_mipi_probe(struct platform_device *pdev) |
359 | { | 440 | { |
360 | struct sh_mipi *mipi; | 441 | struct sh_mipi *mipi; |
@@ -363,11 +444,13 @@ static int __init sh_mipi_probe(struct platform_device *pdev) | |||
363 | struct resource *res2 = platform_get_resource(pdev, IORESOURCE_MEM, 1); | 444 | struct resource *res2 = platform_get_resource(pdev, IORESOURCE_MEM, 1); |
364 | unsigned long rate, f_current; | 445 | unsigned long rate, f_current; |
365 | int idx = pdev->id, ret; | 446 | int idx = pdev->id, ret; |
366 | char dsip_clk[] = "dsi.p_clk"; | ||
367 | 447 | ||
368 | if (!res || !res2 || idx >= ARRAY_SIZE(mipi_dsi) || !pdata) | 448 | if (!res || !res2 || idx >= ARRAY_SIZE(mipi_dsi) || !pdata) |
369 | return -ENODEV; | 449 | return -ENODEV; |
370 | 450 | ||
451 | if (!pdata->set_dot_clock) | ||
452 | return -EINVAL; | ||
453 | |||
371 | mutex_lock(&array_lock); | 454 | mutex_lock(&array_lock); |
372 | if (idx < 0) | 455 | if (idx < 0) |
373 | for (idx = 0; idx < ARRAY_SIZE(mipi_dsi) && mipi_dsi[idx]; idx++) | 456 | for (idx = 0; idx < ARRAY_SIZE(mipi_dsi) && mipi_dsi[idx]; idx++) |
@@ -408,7 +491,7 @@ static int __init sh_mipi_probe(struct platform_device *pdev) | |||
408 | goto emap2; | 491 | goto emap2; |
409 | } | 492 | } |
410 | 493 | ||
411 | mipi->dev = &pdev->dev; | 494 | mipi->pdev = pdev; |
412 | 495 | ||
413 | mipi->dsit_clk = clk_get(&pdev->dev, "dsit_clk"); | 496 | mipi->dsit_clk = clk_get(&pdev->dev, "dsit_clk"); |
414 | if (IS_ERR(mipi->dsit_clk)) { | 497 | if (IS_ERR(mipi->dsit_clk)) { |
@@ -428,44 +511,15 @@ static int __init sh_mipi_probe(struct platform_device *pdev) | |||
428 | 511 | ||
429 | dev_dbg(&pdev->dev, "DSI-T clk %lu -> %lu\n", f_current, rate); | 512 | dev_dbg(&pdev->dev, "DSI-T clk %lu -> %lu\n", f_current, rate); |
430 | 513 | ||
431 | sprintf(dsip_clk, "dsi%1.1dp_clk", idx); | ||
432 | mipi->dsip_clk = clk_get(&pdev->dev, dsip_clk); | ||
433 | if (IS_ERR(mipi->dsip_clk)) { | ||
434 | ret = PTR_ERR(mipi->dsip_clk); | ||
435 | goto eclkpget; | ||
436 | } | ||
437 | |||
438 | f_current = clk_get_rate(mipi->dsip_clk); | ||
439 | /* Between 10 and 50MHz */ | ||
440 | rate = clk_round_rate(mipi->dsip_clk, 24000000); | ||
441 | if (rate > 0 && rate != f_current) | ||
442 | ret = clk_set_rate(mipi->dsip_clk, rate); | ||
443 | else | ||
444 | ret = rate; | ||
445 | if (ret < 0) | ||
446 | goto esetprate; | ||
447 | |||
448 | dev_dbg(&pdev->dev, "DSI-P clk %lu -> %lu\n", f_current, rate); | ||
449 | |||
450 | msleep(10); | ||
451 | |||
452 | ret = clk_enable(mipi->dsit_clk); | 514 | ret = clk_enable(mipi->dsit_clk); |
453 | if (ret < 0) | 515 | if (ret < 0) |
454 | goto eclkton; | 516 | goto eclkton; |
455 | 517 | ||
456 | ret = clk_enable(mipi->dsip_clk); | ||
457 | if (ret < 0) | ||
458 | goto eclkpon; | ||
459 | |||
460 | mipi_dsi[idx] = mipi; | 518 | mipi_dsi[idx] = mipi; |
461 | 519 | ||
462 | pm_runtime_enable(&pdev->dev); | 520 | pm_runtime_enable(&pdev->dev); |
463 | pm_runtime_resume(&pdev->dev); | 521 | pm_runtime_resume(&pdev->dev); |
464 | 522 | ||
465 | ret = sh_mipi_setup(mipi, pdata); | ||
466 | if (ret < 0) | ||
467 | goto emipisetup; | ||
468 | |||
469 | mutex_unlock(&array_lock); | 523 | mutex_unlock(&array_lock); |
470 | platform_set_drvdata(pdev, mipi); | 524 | platform_set_drvdata(pdev, mipi); |
471 | 525 | ||
@@ -482,16 +536,7 @@ static int __init sh_mipi_probe(struct platform_device *pdev) | |||
482 | 536 | ||
483 | return 0; | 537 | return 0; |
484 | 538 | ||
485 | emipisetup: | ||
486 | mipi_dsi[idx] = NULL; | ||
487 | pm_runtime_disable(&pdev->dev); | ||
488 | clk_disable(mipi->dsip_clk); | ||
489 | eclkpon: | ||
490 | clk_disable(mipi->dsit_clk); | ||
491 | eclkton: | 539 | eclkton: |
492 | esetprate: | ||
493 | clk_put(mipi->dsip_clk); | ||
494 | eclkpget: | ||
495 | esettrate: | 540 | esettrate: |
496 | clk_put(mipi->dsit_clk); | 541 | clk_put(mipi->dsit_clk); |
497 | eclktget: | 542 | eclktget: |
@@ -542,10 +587,9 @@ static int __exit sh_mipi_remove(struct platform_device *pdev) | |||
542 | pdata->lcd_chan->board_cfg.board_data = NULL; | 587 | pdata->lcd_chan->board_cfg.board_data = NULL; |
543 | 588 | ||
544 | pm_runtime_disable(&pdev->dev); | 589 | pm_runtime_disable(&pdev->dev); |
545 | clk_disable(mipi->dsip_clk); | ||
546 | clk_disable(mipi->dsit_clk); | 590 | clk_disable(mipi->dsit_clk); |
547 | clk_put(mipi->dsit_clk); | 591 | clk_put(mipi->dsit_clk); |
548 | clk_put(mipi->dsip_clk); | 592 | |
549 | iounmap(mipi->linkbase); | 593 | iounmap(mipi->linkbase); |
550 | if (res2) | 594 | if (res2) |
551 | release_mem_region(res2->start, resource_size(res2)); | 595 | release_mem_region(res2->start, resource_size(res2)); |
diff --git a/drivers/video/sh_mobile_lcdcfb.c b/drivers/video/sh_mobile_lcdcfb.c index facffc254976..aac5b369d73c 100644 --- a/drivers/video/sh_mobile_lcdcfb.c +++ b/drivers/video/sh_mobile_lcdcfb.c | |||
@@ -17,6 +17,7 @@ | |||
17 | #include <linux/platform_device.h> | 17 | #include <linux/platform_device.h> |
18 | #include <linux/dma-mapping.h> | 18 | #include <linux/dma-mapping.h> |
19 | #include <linux/interrupt.h> | 19 | #include <linux/interrupt.h> |
20 | #include <linux/videodev2.h> | ||
20 | #include <linux/vmalloc.h> | 21 | #include <linux/vmalloc.h> |
21 | #include <linux/ioctl.h> | 22 | #include <linux/ioctl.h> |
22 | #include <linux/slab.h> | 23 | #include <linux/slab.h> |
@@ -102,7 +103,7 @@ struct sh_mobile_lcdc_priv { | |||
102 | struct sh_mobile_lcdc_chan ch[2]; | 103 | struct sh_mobile_lcdc_chan ch[2]; |
103 | struct notifier_block notifier; | 104 | struct notifier_block notifier; |
104 | int started; | 105 | int started; |
105 | int forced_bpp; /* 2 channel LCDC must share bpp setting */ | 106 | int forced_fourcc; /* 2 channel LCDC must share fourcc setting */ |
106 | struct sh_mobile_meram_info *meram_dev; | 107 | struct sh_mobile_meram_info *meram_dev; |
107 | }; | 108 | }; |
108 | 109 | ||
@@ -215,6 +216,47 @@ struct sh_mobile_lcdc_sys_bus_ops sh_mobile_lcdc_sys_bus_ops = { | |||
215 | lcdc_sys_read_data, | 216 | lcdc_sys_read_data, |
216 | }; | 217 | }; |
217 | 218 | ||
219 | static int sh_mobile_format_fourcc(const struct fb_var_screeninfo *var) | ||
220 | { | ||
221 | if (var->grayscale > 1) | ||
222 | return var->grayscale; | ||
223 | |||
224 | switch (var->bits_per_pixel) { | ||
225 | case 16: | ||
226 | return V4L2_PIX_FMT_RGB565; | ||
227 | case 24: | ||
228 | return V4L2_PIX_FMT_BGR24; | ||
229 | case 32: | ||
230 | return V4L2_PIX_FMT_BGR32; | ||
231 | default: | ||
232 | return 0; | ||
233 | } | ||
234 | } | ||
235 | |||
236 | static int sh_mobile_format_is_fourcc(const struct fb_var_screeninfo *var) | ||
237 | { | ||
238 | return var->grayscale > 1; | ||
239 | } | ||
240 | |||
241 | static bool sh_mobile_format_is_yuv(const struct fb_var_screeninfo *var) | ||
242 | { | ||
243 | if (var->grayscale <= 1) | ||
244 | return false; | ||
245 | |||
246 | switch (var->grayscale) { | ||
247 | case V4L2_PIX_FMT_NV12: | ||
248 | case V4L2_PIX_FMT_NV21: | ||
249 | case V4L2_PIX_FMT_NV16: | ||
250 | case V4L2_PIX_FMT_NV61: | ||
251 | case V4L2_PIX_FMT_NV24: | ||
252 | case V4L2_PIX_FMT_NV42: | ||
253 | return true; | ||
254 | |||
255 | default: | ||
256 | return false; | ||
257 | } | ||
258 | } | ||
259 | |||
218 | static void sh_mobile_lcdc_clk_on(struct sh_mobile_lcdc_priv *priv) | 260 | static void sh_mobile_lcdc_clk_on(struct sh_mobile_lcdc_priv *priv) |
219 | { | 261 | { |
220 | if (atomic_inc_and_test(&priv->hw_usecnt)) { | 262 | if (atomic_inc_and_test(&priv->hw_usecnt)) { |
@@ -420,7 +462,7 @@ static void sh_mobile_lcdc_geometry(struct sh_mobile_lcdc_chan *ch) | |||
420 | tmp = ((display_var->xres & 7) << 24) | | 462 | tmp = ((display_var->xres & 7) << 24) | |
421 | ((display_h_total & 7) << 16) | | 463 | ((display_h_total & 7) << 16) | |
422 | ((display_var->hsync_len & 7) << 8) | | 464 | ((display_var->hsync_len & 7) << 8) | |
423 | hsync_pos; | 465 | (hsync_pos & 7); |
424 | lcdc_write_chan(ch, LDHAJR, tmp); | 466 | lcdc_write_chan(ch, LDHAJR, tmp); |
425 | } | 467 | } |
426 | 468 | ||
@@ -435,7 +477,6 @@ static void __sh_mobile_lcdc_start(struct sh_mobile_lcdc_priv *priv) | |||
435 | { | 477 | { |
436 | struct sh_mobile_lcdc_chan *ch; | 478 | struct sh_mobile_lcdc_chan *ch; |
437 | unsigned long tmp; | 479 | unsigned long tmp; |
438 | int bpp = 0; | ||
439 | int k, m; | 480 | int k, m; |
440 | 481 | ||
441 | /* Enable LCDC channels. Read data from external memory, avoid using the | 482 | /* Enable LCDC channels. Read data from external memory, avoid using the |
@@ -454,9 +495,6 @@ static void __sh_mobile_lcdc_start(struct sh_mobile_lcdc_priv *priv) | |||
454 | if (!ch->enabled) | 495 | if (!ch->enabled) |
455 | continue; | 496 | continue; |
456 | 497 | ||
457 | if (!bpp) | ||
458 | bpp = ch->info->var.bits_per_pixel; | ||
459 | |||
460 | /* Power supply */ | 498 | /* Power supply */ |
461 | lcdc_write_chan(ch, LDPMR, 0); | 499 | lcdc_write_chan(ch, LDPMR, 0); |
462 | 500 | ||
@@ -487,31 +525,37 @@ static void __sh_mobile_lcdc_start(struct sh_mobile_lcdc_priv *priv) | |||
487 | 525 | ||
488 | sh_mobile_lcdc_geometry(ch); | 526 | sh_mobile_lcdc_geometry(ch); |
489 | 527 | ||
490 | if (ch->info->var.nonstd) { | 528 | switch (sh_mobile_format_fourcc(&ch->info->var)) { |
491 | tmp = (ch->info->var.nonstd << 16); | 529 | case V4L2_PIX_FMT_RGB565: |
492 | switch (ch->info->var.bits_per_pixel) { | 530 | tmp = LDDFR_PKF_RGB16; |
493 | case 12: | 531 | break; |
494 | tmp |= LDDFR_YF_420; | 532 | case V4L2_PIX_FMT_BGR24: |
495 | break; | 533 | tmp = LDDFR_PKF_RGB24; |
496 | case 16: | 534 | break; |
497 | tmp |= LDDFR_YF_422; | 535 | case V4L2_PIX_FMT_BGR32: |
498 | break; | 536 | tmp = LDDFR_PKF_ARGB32; |
499 | case 24: | 537 | break; |
500 | default: | 538 | case V4L2_PIX_FMT_NV12: |
501 | tmp |= LDDFR_YF_444; | 539 | case V4L2_PIX_FMT_NV21: |
502 | break; | 540 | tmp = LDDFR_CC | LDDFR_YF_420; |
503 | } | 541 | break; |
504 | } else { | 542 | case V4L2_PIX_FMT_NV16: |
505 | switch (ch->info->var.bits_per_pixel) { | 543 | case V4L2_PIX_FMT_NV61: |
506 | case 16: | 544 | tmp = LDDFR_CC | LDDFR_YF_422; |
507 | tmp = LDDFR_PKF_RGB16; | 545 | break; |
508 | break; | 546 | case V4L2_PIX_FMT_NV24: |
509 | case 24: | 547 | case V4L2_PIX_FMT_NV42: |
510 | tmp = LDDFR_PKF_RGB24; | 548 | tmp = LDDFR_CC | LDDFR_YF_444; |
549 | break; | ||
550 | } | ||
551 | |||
552 | if (sh_mobile_format_is_yuv(&ch->info->var)) { | ||
553 | switch (ch->info->var.colorspace) { | ||
554 | case V4L2_COLORSPACE_REC709: | ||
555 | tmp |= LDDFR_CF1; | ||
511 | break; | 556 | break; |
512 | case 32: | 557 | case V4L2_COLORSPACE_JPEG: |
513 | default: | 558 | tmp |= LDDFR_CF0; |
514 | tmp = LDDFR_PKF_ARGB32; | ||
515 | break; | 559 | break; |
516 | } | 560 | } |
517 | } | 561 | } |
@@ -519,7 +563,7 @@ static void __sh_mobile_lcdc_start(struct sh_mobile_lcdc_priv *priv) | |||
519 | lcdc_write_chan(ch, LDDFR, tmp); | 563 | lcdc_write_chan(ch, LDDFR, tmp); |
520 | lcdc_write_chan(ch, LDMLSR, ch->pitch); | 564 | lcdc_write_chan(ch, LDMLSR, ch->pitch); |
521 | lcdc_write_chan(ch, LDSA1R, ch->base_addr_y); | 565 | lcdc_write_chan(ch, LDSA1R, ch->base_addr_y); |
522 | if (ch->info->var.nonstd) | 566 | if (sh_mobile_format_is_yuv(&ch->info->var)) |
523 | lcdc_write_chan(ch, LDSA2R, ch->base_addr_c); | 567 | lcdc_write_chan(ch, LDSA2R, ch->base_addr_c); |
524 | 568 | ||
525 | /* When using deferred I/O mode, configure the LCDC for one-shot | 569 | /* When using deferred I/O mode, configure the LCDC for one-shot |
@@ -536,21 +580,23 @@ static void __sh_mobile_lcdc_start(struct sh_mobile_lcdc_priv *priv) | |||
536 | } | 580 | } |
537 | 581 | ||
538 | /* Word and long word swap. */ | 582 | /* Word and long word swap. */ |
539 | if (priv->ch[0].info->var.nonstd) | 583 | switch (sh_mobile_format_fourcc(&priv->ch[0].info->var)) { |
584 | case V4L2_PIX_FMT_RGB565: | ||
585 | case V4L2_PIX_FMT_NV21: | ||
586 | case V4L2_PIX_FMT_NV61: | ||
587 | case V4L2_PIX_FMT_NV42: | ||
588 | tmp = LDDDSR_LS | LDDDSR_WS; | ||
589 | break; | ||
590 | case V4L2_PIX_FMT_BGR24: | ||
591 | case V4L2_PIX_FMT_NV12: | ||
592 | case V4L2_PIX_FMT_NV16: | ||
593 | case V4L2_PIX_FMT_NV24: | ||
540 | tmp = LDDDSR_LS | LDDDSR_WS | LDDDSR_BS; | 594 | tmp = LDDDSR_LS | LDDDSR_WS | LDDDSR_BS; |
541 | else { | 595 | break; |
542 | switch (bpp) { | 596 | case V4L2_PIX_FMT_BGR32: |
543 | case 16: | 597 | default: |
544 | tmp = LDDDSR_LS | LDDDSR_WS; | 598 | tmp = LDDDSR_LS; |
545 | break; | 599 | break; |
546 | case 24: | ||
547 | tmp = LDDDSR_LS | LDDDSR_WS | LDDDSR_BS; | ||
548 | break; | ||
549 | case 32: | ||
550 | default: | ||
551 | tmp = LDDDSR_LS; | ||
552 | break; | ||
553 | } | ||
554 | } | 600 | } |
555 | lcdc_write(priv, _LDDDSR, tmp); | 601 | lcdc_write(priv, _LDDDSR, tmp); |
556 | 602 | ||
@@ -622,12 +668,24 @@ static int sh_mobile_lcdc_start(struct sh_mobile_lcdc_priv *priv) | |||
622 | ch->meram_enabled = 0; | 668 | ch->meram_enabled = 0; |
623 | } | 669 | } |
624 | 670 | ||
625 | if (!ch->info->var.nonstd) | 671 | switch (sh_mobile_format_fourcc(&ch->info->var)) { |
626 | pixelformat = SH_MOBILE_MERAM_PF_RGB; | 672 | case V4L2_PIX_FMT_NV12: |
627 | else if (ch->info->var.bits_per_pixel == 24) | 673 | case V4L2_PIX_FMT_NV21: |
628 | pixelformat = SH_MOBILE_MERAM_PF_NV24; | 674 | case V4L2_PIX_FMT_NV16: |
629 | else | 675 | case V4L2_PIX_FMT_NV61: |
630 | pixelformat = SH_MOBILE_MERAM_PF_NV; | 676 | pixelformat = SH_MOBILE_MERAM_PF_NV; |
677 | break; | ||
678 | case V4L2_PIX_FMT_NV24: | ||
679 | case V4L2_PIX_FMT_NV42: | ||
680 | pixelformat = SH_MOBILE_MERAM_PF_NV24; | ||
681 | break; | ||
682 | case V4L2_PIX_FMT_RGB565: | ||
683 | case V4L2_PIX_FMT_BGR24: | ||
684 | case V4L2_PIX_FMT_BGR32: | ||
685 | default: | ||
686 | pixelformat = SH_MOBILE_MERAM_PF_RGB; | ||
687 | break; | ||
688 | } | ||
631 | 689 | ||
632 | ret = mdev->ops->meram_register(mdev, cfg, ch->pitch, | 690 | ret = mdev->ops->meram_register(mdev, cfg, ch->pitch, |
633 | ch->info->var.yres, pixelformat, | 691 | ch->info->var.yres, pixelformat, |
@@ -845,6 +903,7 @@ static struct fb_fix_screeninfo sh_mobile_lcdc_fix = { | |||
845 | .xpanstep = 0, | 903 | .xpanstep = 0, |
846 | .ypanstep = 1, | 904 | .ypanstep = 1, |
847 | .ywrapstep = 0, | 905 | .ywrapstep = 0, |
906 | .capabilities = FB_CAP_FOURCC, | ||
848 | }; | 907 | }; |
849 | 908 | ||
850 | static void sh_mobile_lcdc_fillrect(struct fb_info *info, | 909 | static void sh_mobile_lcdc_fillrect(struct fb_info *info, |
@@ -877,8 +936,9 @@ static int sh_mobile_fb_pan_display(struct fb_var_screeninfo *var, | |||
877 | unsigned long new_pan_offset; | 936 | unsigned long new_pan_offset; |
878 | unsigned long base_addr_y, base_addr_c; | 937 | unsigned long base_addr_y, base_addr_c; |
879 | unsigned long c_offset; | 938 | unsigned long c_offset; |
939 | bool yuv = sh_mobile_format_is_yuv(&info->var); | ||
880 | 940 | ||
881 | if (!info->var.nonstd) | 941 | if (!yuv) |
882 | new_pan_offset = var->yoffset * info->fix.line_length | 942 | new_pan_offset = var->yoffset * info->fix.line_length |
883 | + var->xoffset * (info->var.bits_per_pixel / 8); | 943 | + var->xoffset * (info->var.bits_per_pixel / 8); |
884 | else | 944 | else |
@@ -892,7 +952,7 @@ static int sh_mobile_fb_pan_display(struct fb_var_screeninfo *var, | |||
892 | 952 | ||
893 | /* Set the source address for the next refresh */ | 953 | /* Set the source address for the next refresh */ |
894 | base_addr_y = ch->dma_handle + new_pan_offset; | 954 | base_addr_y = ch->dma_handle + new_pan_offset; |
895 | if (info->var.nonstd) { | 955 | if (yuv) { |
896 | /* Set y offset */ | 956 | /* Set y offset */ |
897 | c_offset = var->yoffset * info->fix.line_length | 957 | c_offset = var->yoffset * info->fix.line_length |
898 | * (info->var.bits_per_pixel - 8) / 8; | 958 | * (info->var.bits_per_pixel - 8) / 8; |
@@ -900,7 +960,7 @@ static int sh_mobile_fb_pan_display(struct fb_var_screeninfo *var, | |||
900 | + info->var.xres * info->var.yres_virtual | 960 | + info->var.xres * info->var.yres_virtual |
901 | + c_offset; | 961 | + c_offset; |
902 | /* Set x offset */ | 962 | /* Set x offset */ |
903 | if (info->var.bits_per_pixel == 24) | 963 | if (sh_mobile_format_fourcc(&info->var) == V4L2_PIX_FMT_NV24) |
904 | base_addr_c += 2 * var->xoffset; | 964 | base_addr_c += 2 * var->xoffset; |
905 | else | 965 | else |
906 | base_addr_c += var->xoffset; | 966 | base_addr_c += var->xoffset; |
@@ -924,7 +984,7 @@ static int sh_mobile_fb_pan_display(struct fb_var_screeninfo *var, | |||
924 | ch->base_addr_c = base_addr_c; | 984 | ch->base_addr_c = base_addr_c; |
925 | 985 | ||
926 | lcdc_write_chan_mirror(ch, LDSA1R, base_addr_y); | 986 | lcdc_write_chan_mirror(ch, LDSA1R, base_addr_y); |
927 | if (info->var.nonstd) | 987 | if (yuv) |
928 | lcdc_write_chan_mirror(ch, LDSA2R, base_addr_c); | 988 | lcdc_write_chan_mirror(ch, LDSA2R, base_addr_c); |
929 | 989 | ||
930 | if (lcdc_chan_is_sublcd(ch)) | 990 | if (lcdc_chan_is_sublcd(ch)) |
@@ -1100,51 +1160,84 @@ static int sh_mobile_check_var(struct fb_var_screeninfo *var, struct fb_info *in | |||
1100 | if (var->yres_virtual < var->yres) | 1160 | if (var->yres_virtual < var->yres) |
1101 | var->yres_virtual = var->yres; | 1161 | var->yres_virtual = var->yres; |
1102 | 1162 | ||
1103 | if (var->bits_per_pixel <= 16) { /* RGB 565 */ | 1163 | if (sh_mobile_format_is_fourcc(var)) { |
1104 | var->bits_per_pixel = 16; | 1164 | switch (var->grayscale) { |
1105 | var->red.offset = 11; | 1165 | case V4L2_PIX_FMT_NV12: |
1106 | var->red.length = 5; | 1166 | case V4L2_PIX_FMT_NV21: |
1107 | var->green.offset = 5; | 1167 | var->bits_per_pixel = 12; |
1108 | var->green.length = 6; | 1168 | break; |
1109 | var->blue.offset = 0; | 1169 | case V4L2_PIX_FMT_RGB565: |
1110 | var->blue.length = 5; | 1170 | case V4L2_PIX_FMT_NV16: |
1111 | var->transp.offset = 0; | 1171 | case V4L2_PIX_FMT_NV61: |
1112 | var->transp.length = 0; | 1172 | var->bits_per_pixel = 16; |
1113 | } else if (var->bits_per_pixel <= 24) { /* RGB 888 */ | 1173 | break; |
1114 | var->bits_per_pixel = 24; | 1174 | case V4L2_PIX_FMT_BGR24: |
1115 | var->red.offset = 16; | 1175 | case V4L2_PIX_FMT_NV24: |
1116 | var->red.length = 8; | 1176 | case V4L2_PIX_FMT_NV42: |
1117 | var->green.offset = 8; | 1177 | var->bits_per_pixel = 24; |
1118 | var->green.length = 8; | 1178 | break; |
1119 | var->blue.offset = 0; | 1179 | case V4L2_PIX_FMT_BGR32: |
1120 | var->blue.length = 8; | 1180 | var->bits_per_pixel = 32; |
1121 | var->transp.offset = 0; | 1181 | break; |
1122 | var->transp.length = 0; | 1182 | default: |
1123 | } else if (var->bits_per_pixel <= 32) { /* RGBA 888 */ | 1183 | return -EINVAL; |
1124 | var->bits_per_pixel = 32; | 1184 | } |
1125 | var->red.offset = 16; | ||
1126 | var->red.length = 8; | ||
1127 | var->green.offset = 8; | ||
1128 | var->green.length = 8; | ||
1129 | var->blue.offset = 0; | ||
1130 | var->blue.length = 8; | ||
1131 | var->transp.offset = 24; | ||
1132 | var->transp.length = 8; | ||
1133 | } else | ||
1134 | return -EINVAL; | ||
1135 | 1185 | ||
1136 | var->red.msb_right = 0; | 1186 | /* Default to RGB and JPEG color-spaces for RGB and YUV formats |
1137 | var->green.msb_right = 0; | 1187 | * respectively. |
1138 | var->blue.msb_right = 0; | 1188 | */ |
1139 | var->transp.msb_right = 0; | 1189 | if (!sh_mobile_format_is_yuv(var)) |
1190 | var->colorspace = V4L2_COLORSPACE_SRGB; | ||
1191 | else if (var->colorspace != V4L2_COLORSPACE_REC709) | ||
1192 | var->colorspace = V4L2_COLORSPACE_JPEG; | ||
1193 | } else { | ||
1194 | if (var->bits_per_pixel <= 16) { /* RGB 565 */ | ||
1195 | var->bits_per_pixel = 16; | ||
1196 | var->red.offset = 11; | ||
1197 | var->red.length = 5; | ||
1198 | var->green.offset = 5; | ||
1199 | var->green.length = 6; | ||
1200 | var->blue.offset = 0; | ||
1201 | var->blue.length = 5; | ||
1202 | var->transp.offset = 0; | ||
1203 | var->transp.length = 0; | ||
1204 | } else if (var->bits_per_pixel <= 24) { /* RGB 888 */ | ||
1205 | var->bits_per_pixel = 24; | ||
1206 | var->red.offset = 16; | ||
1207 | var->red.length = 8; | ||
1208 | var->green.offset = 8; | ||
1209 | var->green.length = 8; | ||
1210 | var->blue.offset = 0; | ||
1211 | var->blue.length = 8; | ||
1212 | var->transp.offset = 0; | ||
1213 | var->transp.length = 0; | ||
1214 | } else if (var->bits_per_pixel <= 32) { /* RGBA 888 */ | ||
1215 | var->bits_per_pixel = 32; | ||
1216 | var->red.offset = 16; | ||
1217 | var->red.length = 8; | ||
1218 | var->green.offset = 8; | ||
1219 | var->green.length = 8; | ||
1220 | var->blue.offset = 0; | ||
1221 | var->blue.length = 8; | ||
1222 | var->transp.offset = 24; | ||
1223 | var->transp.length = 8; | ||
1224 | } else | ||
1225 | return -EINVAL; | ||
1226 | |||
1227 | var->red.msb_right = 0; | ||
1228 | var->green.msb_right = 0; | ||
1229 | var->blue.msb_right = 0; | ||
1230 | var->transp.msb_right = 0; | ||
1231 | } | ||
1140 | 1232 | ||
1141 | /* Make sure we don't exceed our allocated memory. */ | 1233 | /* Make sure we don't exceed our allocated memory. */ |
1142 | if (var->xres_virtual * var->yres_virtual * var->bits_per_pixel / 8 > | 1234 | if (var->xres_virtual * var->yres_virtual * var->bits_per_pixel / 8 > |
1143 | info->fix.smem_len) | 1235 | info->fix.smem_len) |
1144 | return -EINVAL; | 1236 | return -EINVAL; |
1145 | 1237 | ||
1146 | /* only accept the forced_bpp for dual channel configurations */ | 1238 | /* only accept the forced_fourcc for dual channel configurations */ |
1147 | if (p->forced_bpp && p->forced_bpp != var->bits_per_pixel) | 1239 | if (p->forced_fourcc && |
1240 | p->forced_fourcc != sh_mobile_format_fourcc(var)) | ||
1148 | return -EINVAL; | 1241 | return -EINVAL; |
1149 | 1242 | ||
1150 | return 0; | 1243 | return 0; |
@@ -1158,7 +1251,7 @@ static int sh_mobile_set_par(struct fb_info *info) | |||
1158 | 1251 | ||
1159 | sh_mobile_lcdc_stop(ch->lcdc); | 1252 | sh_mobile_lcdc_stop(ch->lcdc); |
1160 | 1253 | ||
1161 | if (info->var.nonstd) | 1254 | if (sh_mobile_format_is_yuv(&info->var)) |
1162 | info->fix.line_length = info->var.xres; | 1255 | info->fix.line_length = info->var.xres; |
1163 | else | 1256 | else |
1164 | info->fix.line_length = info->var.xres | 1257 | info->fix.line_length = info->var.xres |
@@ -1170,6 +1263,14 @@ static int sh_mobile_set_par(struct fb_info *info) | |||
1170 | info->fix.line_length = line_length; | 1263 | info->fix.line_length = line_length; |
1171 | } | 1264 | } |
1172 | 1265 | ||
1266 | if (sh_mobile_format_is_fourcc(&info->var)) { | ||
1267 | info->fix.type = FB_TYPE_FOURCC; | ||
1268 | info->fix.visual = FB_VISUAL_FOURCC; | ||
1269 | } else { | ||
1270 | info->fix.type = FB_TYPE_PACKED_PIXELS; | ||
1271 | info->fix.visual = FB_VISUAL_TRUECOLOR; | ||
1272 | } | ||
1273 | |||
1173 | return ret; | 1274 | return ret; |
1174 | } | 1275 | } |
1175 | 1276 | ||
@@ -1464,9 +1565,9 @@ static int __devinit sh_mobile_lcdc_channel_init(struct sh_mobile_lcdc_chan *ch, | |||
1464 | for (i = 0, mode = cfg->lcd_cfg; i < cfg->num_cfg; i++, mode++) { | 1565 | for (i = 0, mode = cfg->lcd_cfg; i < cfg->num_cfg; i++, mode++) { |
1465 | unsigned int size = mode->yres * mode->xres; | 1566 | unsigned int size = mode->yres * mode->xres; |
1466 | 1567 | ||
1467 | /* NV12 buffers must have even number of lines */ | 1568 | /* NV12/NV21 buffers must have even number of lines */ |
1468 | if ((cfg->nonstd) && cfg->bpp == 12 && | 1569 | if ((cfg->fourcc == V4L2_PIX_FMT_NV12 || |
1469 | (mode->yres & 0x1)) { | 1570 | cfg->fourcc == V4L2_PIX_FMT_NV21) && (mode->yres & 0x1)) { |
1470 | dev_err(dev, "yres must be multiple of 2 for YCbCr420 " | 1571 | dev_err(dev, "yres must be multiple of 2 for YCbCr420 " |
1471 | "mode.\n"); | 1572 | "mode.\n"); |
1472 | return -EINVAL; | 1573 | return -EINVAL; |
@@ -1484,14 +1585,6 @@ static int __devinit sh_mobile_lcdc_channel_init(struct sh_mobile_lcdc_chan *ch, | |||
1484 | dev_dbg(dev, "Found largest videomode %ux%u\n", | 1585 | dev_dbg(dev, "Found largest videomode %ux%u\n", |
1485 | max_mode->xres, max_mode->yres); | 1586 | max_mode->xres, max_mode->yres); |
1486 | 1587 | ||
1487 | /* Initialize fixed screen information. Restrict pan to 2 lines steps | ||
1488 | * for NV12. | ||
1489 | */ | ||
1490 | info->fix = sh_mobile_lcdc_fix; | ||
1491 | info->fix.smem_len = max_size * 2 * cfg->bpp / 8; | ||
1492 | if (cfg->nonstd && cfg->bpp == 12) | ||
1493 | info->fix.ypanstep = 2; | ||
1494 | |||
1495 | /* Create the mode list. */ | 1588 | /* Create the mode list. */ |
1496 | if (cfg->lcd_cfg == NULL) { | 1589 | if (cfg->lcd_cfg == NULL) { |
1497 | mode = &default_720p; | 1590 | mode = &default_720p; |
@@ -1509,19 +1602,38 @@ static int __devinit sh_mobile_lcdc_channel_init(struct sh_mobile_lcdc_chan *ch, | |||
1509 | */ | 1602 | */ |
1510 | var = &info->var; | 1603 | var = &info->var; |
1511 | fb_videomode_to_var(var, mode); | 1604 | fb_videomode_to_var(var, mode); |
1512 | var->bits_per_pixel = cfg->bpp; | ||
1513 | var->width = cfg->lcd_size_cfg.width; | 1605 | var->width = cfg->lcd_size_cfg.width; |
1514 | var->height = cfg->lcd_size_cfg.height; | 1606 | var->height = cfg->lcd_size_cfg.height; |
1515 | var->yres_virtual = var->yres * 2; | 1607 | var->yres_virtual = var->yres * 2; |
1516 | var->activate = FB_ACTIVATE_NOW; | 1608 | var->activate = FB_ACTIVATE_NOW; |
1517 | 1609 | ||
1610 | switch (cfg->fourcc) { | ||
1611 | case V4L2_PIX_FMT_RGB565: | ||
1612 | var->bits_per_pixel = 16; | ||
1613 | break; | ||
1614 | case V4L2_PIX_FMT_BGR24: | ||
1615 | var->bits_per_pixel = 24; | ||
1616 | break; | ||
1617 | case V4L2_PIX_FMT_BGR32: | ||
1618 | var->bits_per_pixel = 32; | ||
1619 | break; | ||
1620 | default: | ||
1621 | var->grayscale = cfg->fourcc; | ||
1622 | break; | ||
1623 | } | ||
1624 | |||
1625 | /* Make sure the memory size check won't fail. smem_len is initialized | ||
1626 | * later based on var. | ||
1627 | */ | ||
1628 | info->fix.smem_len = UINT_MAX; | ||
1518 | ret = sh_mobile_check_var(var, info); | 1629 | ret = sh_mobile_check_var(var, info); |
1519 | if (ret) | 1630 | if (ret) |
1520 | return ret; | 1631 | return ret; |
1521 | 1632 | ||
1633 | max_size = max_size * var->bits_per_pixel / 8 * 2; | ||
1634 | |||
1522 | /* Allocate frame buffer memory and color map. */ | 1635 | /* Allocate frame buffer memory and color map. */ |
1523 | buf = dma_alloc_coherent(dev, info->fix.smem_len, &ch->dma_handle, | 1636 | buf = dma_alloc_coherent(dev, max_size, &ch->dma_handle, GFP_KERNEL); |
1524 | GFP_KERNEL); | ||
1525 | if (!buf) { | 1637 | if (!buf) { |
1526 | dev_err(dev, "unable to allocate buffer\n"); | 1638 | dev_err(dev, "unable to allocate buffer\n"); |
1527 | return -ENOMEM; | 1639 | return -ENOMEM; |
@@ -1530,16 +1642,27 @@ static int __devinit sh_mobile_lcdc_channel_init(struct sh_mobile_lcdc_chan *ch, | |||
1530 | ret = fb_alloc_cmap(&info->cmap, PALETTE_NR, 0); | 1642 | ret = fb_alloc_cmap(&info->cmap, PALETTE_NR, 0); |
1531 | if (ret < 0) { | 1643 | if (ret < 0) { |
1532 | dev_err(dev, "unable to allocate cmap\n"); | 1644 | dev_err(dev, "unable to allocate cmap\n"); |
1533 | dma_free_coherent(dev, info->fix.smem_len, | 1645 | dma_free_coherent(dev, max_size, buf, ch->dma_handle); |
1534 | buf, ch->dma_handle); | ||
1535 | return ret; | 1646 | return ret; |
1536 | } | 1647 | } |
1537 | 1648 | ||
1649 | /* Initialize fixed screen information. Restrict pan to 2 lines steps | ||
1650 | * for NV12 and NV21. | ||
1651 | */ | ||
1652 | info->fix = sh_mobile_lcdc_fix; | ||
1538 | info->fix.smem_start = ch->dma_handle; | 1653 | info->fix.smem_start = ch->dma_handle; |
1539 | if (var->nonstd) | 1654 | info->fix.smem_len = max_size; |
1655 | if (cfg->fourcc == V4L2_PIX_FMT_NV12 || | ||
1656 | cfg->fourcc == V4L2_PIX_FMT_NV21) | ||
1657 | info->fix.ypanstep = 2; | ||
1658 | |||
1659 | if (sh_mobile_format_is_yuv(var)) { | ||
1540 | info->fix.line_length = var->xres; | 1660 | info->fix.line_length = var->xres; |
1541 | else | 1661 | info->fix.visual = FB_VISUAL_FOURCC; |
1542 | info->fix.line_length = var->xres * (cfg->bpp / 8); | 1662 | } else { |
1663 | info->fix.line_length = var->xres * var->bits_per_pixel / 8; | ||
1664 | info->fix.visual = FB_VISUAL_TRUECOLOR; | ||
1665 | } | ||
1543 | 1666 | ||
1544 | info->screen_base = buf; | 1667 | info->screen_base = buf; |
1545 | info->device = dev; | 1668 | info->device = dev; |
@@ -1626,9 +1749,9 @@ static int __devinit sh_mobile_lcdc_probe(struct platform_device *pdev) | |||
1626 | goto err1; | 1749 | goto err1; |
1627 | } | 1750 | } |
1628 | 1751 | ||
1629 | /* for dual channel LCDC (MAIN + SUB) force shared bpp setting */ | 1752 | /* for dual channel LCDC (MAIN + SUB) force shared format setting */ |
1630 | if (num_channels == 2) | 1753 | if (num_channels == 2) |
1631 | priv->forced_bpp = pdata->ch[0].bpp; | 1754 | priv->forced_fourcc = pdata->ch[0].fourcc; |
1632 | 1755 | ||
1633 | priv->base = ioremap_nocache(res->start, resource_size(res)); | 1756 | priv->base = ioremap_nocache(res->start, resource_size(res)); |
1634 | if (!priv->base) | 1757 | if (!priv->base) |
@@ -1675,13 +1798,10 @@ static int __devinit sh_mobile_lcdc_probe(struct platform_device *pdev) | |||
1675 | if (error < 0) | 1798 | if (error < 0) |
1676 | goto err1; | 1799 | goto err1; |
1677 | 1800 | ||
1678 | dev_info(info->dev, | 1801 | dev_info(info->dev, "registered %s/%s as %dx%d %dbpp.\n", |
1679 | "registered %s/%s as %dx%d %dbpp.\n", | 1802 | pdev->name, (ch->cfg.chan == LCDC_CHAN_MAINLCD) ? |
1680 | pdev->name, | 1803 | "mainlcd" : "sublcd", info->var.xres, info->var.yres, |
1681 | (ch->cfg.chan == LCDC_CHAN_MAINLCD) ? | 1804 | info->var.bits_per_pixel); |
1682 | "mainlcd" : "sublcd", | ||
1683 | info->var.xres, info->var.yres, | ||
1684 | ch->cfg.bpp); | ||
1685 | 1805 | ||
1686 | /* deferred io mode: disable clock to save power */ | 1806 | /* deferred io mode: disable clock to save power */ |
1687 | if (info->fbdefio || info->state == FBINFO_STATE_SUSPENDED) | 1807 | if (info->fbdefio || info->state == FBINFO_STATE_SUSPENDED) |
@@ -1709,18 +1829,7 @@ static struct platform_driver sh_mobile_lcdc_driver = { | |||
1709 | .remove = sh_mobile_lcdc_remove, | 1829 | .remove = sh_mobile_lcdc_remove, |
1710 | }; | 1830 | }; |
1711 | 1831 | ||
1712 | static int __init sh_mobile_lcdc_init(void) | 1832 | module_platform_driver(sh_mobile_lcdc_driver); |
1713 | { | ||
1714 | return platform_driver_register(&sh_mobile_lcdc_driver); | ||
1715 | } | ||
1716 | |||
1717 | static void __exit sh_mobile_lcdc_exit(void) | ||
1718 | { | ||
1719 | platform_driver_unregister(&sh_mobile_lcdc_driver); | ||
1720 | } | ||
1721 | |||
1722 | module_init(sh_mobile_lcdc_init); | ||
1723 | module_exit(sh_mobile_lcdc_exit); | ||
1724 | 1833 | ||
1725 | MODULE_DESCRIPTION("SuperH Mobile LCDC Framebuffer driver"); | 1834 | MODULE_DESCRIPTION("SuperH Mobile LCDC Framebuffer driver"); |
1726 | MODULE_AUTHOR("Magnus Damm <damm@opensource.se>"); | 1835 | MODULE_AUTHOR("Magnus Damm <damm@opensource.se>"); |
diff --git a/drivers/video/sh_mobile_meram.c b/drivers/video/sh_mobile_meram.c index 4d63490209cd..f45d83ecfd21 100644 --- a/drivers/video/sh_mobile_meram.c +++ b/drivers/video/sh_mobile_meram.c | |||
@@ -679,18 +679,7 @@ static struct platform_driver sh_mobile_meram_driver = { | |||
679 | .remove = sh_mobile_meram_remove, | 679 | .remove = sh_mobile_meram_remove, |
680 | }; | 680 | }; |
681 | 681 | ||
682 | static int __init sh_mobile_meram_init(void) | 682 | module_platform_driver(sh_mobile_meram_driver); |
683 | { | ||
684 | return platform_driver_register(&sh_mobile_meram_driver); | ||
685 | } | ||
686 | |||
687 | static void __exit sh_mobile_meram_exit(void) | ||
688 | { | ||
689 | platform_driver_unregister(&sh_mobile_meram_driver); | ||
690 | } | ||
691 | |||
692 | module_init(sh_mobile_meram_init); | ||
693 | module_exit(sh_mobile_meram_exit); | ||
694 | 683 | ||
695 | MODULE_DESCRIPTION("SuperH Mobile MERAM driver"); | 684 | MODULE_DESCRIPTION("SuperH Mobile MERAM driver"); |
696 | MODULE_AUTHOR("Damian Hobson-Garcia / Takanari Hayama"); | 685 | MODULE_AUTHOR("Damian Hobson-Garcia / Takanari Hayama"); |
diff --git a/drivers/video/sm501fb.c b/drivers/video/sm501fb.c index a78254cf8e83..3690effbedcc 100644 --- a/drivers/video/sm501fb.c +++ b/drivers/video/sm501fb.c | |||
@@ -2230,18 +2230,7 @@ static struct platform_driver sm501fb_driver = { | |||
2230 | }, | 2230 | }, |
2231 | }; | 2231 | }; |
2232 | 2232 | ||
2233 | static int __devinit sm501fb_init(void) | 2233 | module_platform_driver(sm501fb_driver); |
2234 | { | ||
2235 | return platform_driver_register(&sm501fb_driver); | ||
2236 | } | ||
2237 | |||
2238 | static void __exit sm501fb_cleanup(void) | ||
2239 | { | ||
2240 | platform_driver_unregister(&sm501fb_driver); | ||
2241 | } | ||
2242 | |||
2243 | module_init(sm501fb_init); | ||
2244 | module_exit(sm501fb_cleanup); | ||
2245 | 2234 | ||
2246 | module_param_named(mode, fb_mode, charp, 0); | 2235 | module_param_named(mode, fb_mode, charp, 0); |
2247 | MODULE_PARM_DESC(mode, | 2236 | MODULE_PARM_DESC(mode, |
diff --git a/drivers/video/vt8500lcdfb.c b/drivers/video/vt8500lcdfb.c index 777c21dd7a6b..2a5fe6ede845 100644 --- a/drivers/video/vt8500lcdfb.c +++ b/drivers/video/vt8500lcdfb.c | |||
@@ -457,18 +457,7 @@ static struct platform_driver vt8500lcd_driver = { | |||
457 | }, | 457 | }, |
458 | }; | 458 | }; |
459 | 459 | ||
460 | static int __init vt8500lcd_init(void) | 460 | module_platform_driver(vt8500lcd_driver); |
461 | { | ||
462 | return platform_driver_register(&vt8500lcd_driver); | ||
463 | } | ||
464 | |||
465 | static void __exit vt8500lcd_exit(void) | ||
466 | { | ||
467 | platform_driver_unregister(&vt8500lcd_driver); | ||
468 | } | ||
469 | |||
470 | module_init(vt8500lcd_init); | ||
471 | module_exit(vt8500lcd_exit); | ||
472 | 461 | ||
473 | MODULE_AUTHOR("Alexey Charkov <alchark@gmail.com>"); | 462 | MODULE_AUTHOR("Alexey Charkov <alchark@gmail.com>"); |
474 | MODULE_DESCRIPTION("LCD controller driver for VIA VT8500"); | 463 | MODULE_DESCRIPTION("LCD controller driver for VIA VT8500"); |
diff --git a/drivers/video/w100fb.c b/drivers/video/w100fb.c index 2375e5bbf572..90a2e30272ad 100644 --- a/drivers/video/w100fb.c +++ b/drivers/video/w100fb.c | |||
@@ -1620,18 +1620,7 @@ static struct platform_driver w100fb_driver = { | |||
1620 | }, | 1620 | }, |
1621 | }; | 1621 | }; |
1622 | 1622 | ||
1623 | int __init w100fb_init(void) | 1623 | module_platform_driver(w100fb_driver); |
1624 | { | ||
1625 | return platform_driver_register(&w100fb_driver); | ||
1626 | } | ||
1627 | |||
1628 | void __exit w100fb_cleanup(void) | ||
1629 | { | ||
1630 | platform_driver_unregister(&w100fb_driver); | ||
1631 | } | ||
1632 | |||
1633 | module_init(w100fb_init); | ||
1634 | module_exit(w100fb_cleanup); | ||
1635 | 1624 | ||
1636 | MODULE_DESCRIPTION("ATI Imageon w100 framebuffer driver"); | 1625 | MODULE_DESCRIPTION("ATI Imageon w100 framebuffer driver"); |
1637 | MODULE_LICENSE("GPL"); | 1626 | MODULE_LICENSE("GPL"); |
diff --git a/drivers/video/wm8505fb.c b/drivers/video/wm8505fb.c index 96e34a569169..c8703bd61b74 100644 --- a/drivers/video/wm8505fb.c +++ b/drivers/video/wm8505fb.c | |||
@@ -404,18 +404,7 @@ static struct platform_driver wm8505fb_driver = { | |||
404 | }, | 404 | }, |
405 | }; | 405 | }; |
406 | 406 | ||
407 | static int __init wm8505fb_init(void) | 407 | module_platform_driver(wm8505fb_driver); |
408 | { | ||
409 | return platform_driver_register(&wm8505fb_driver); | ||
410 | } | ||
411 | |||
412 | static void __exit wm8505fb_exit(void) | ||
413 | { | ||
414 | platform_driver_unregister(&wm8505fb_driver); | ||
415 | } | ||
416 | |||
417 | module_init(wm8505fb_init); | ||
418 | module_exit(wm8505fb_exit); | ||
419 | 408 | ||
420 | MODULE_AUTHOR("Ed Spiridonov <edo.rus@gmail.com>"); | 409 | MODULE_AUTHOR("Ed Spiridonov <edo.rus@gmail.com>"); |
421 | MODULE_DESCRIPTION("Framebuffer driver for WMT WM8505"); | 410 | MODULE_DESCRIPTION("Framebuffer driver for WMT WM8505"); |
diff --git a/drivers/video/wmt_ge_rops.c b/drivers/video/wmt_ge_rops.c index 45832b7ef7d2..55be3865015b 100644 --- a/drivers/video/wmt_ge_rops.c +++ b/drivers/video/wmt_ge_rops.c | |||
@@ -167,18 +167,7 @@ static struct platform_driver wmt_ge_rops_driver = { | |||
167 | }, | 167 | }, |
168 | }; | 168 | }; |
169 | 169 | ||
170 | static int __init wmt_ge_rops_init(void) | 170 | module_platform_driver(wmt_ge_rops_driver); |
171 | { | ||
172 | return platform_driver_register(&wmt_ge_rops_driver); | ||
173 | } | ||
174 | |||
175 | static void __exit wmt_ge_rops_exit(void) | ||
176 | { | ||
177 | platform_driver_unregister(&wmt_ge_rops_driver); | ||
178 | } | ||
179 | |||
180 | module_init(wmt_ge_rops_init); | ||
181 | module_exit(wmt_ge_rops_exit); | ||
182 | 171 | ||
183 | MODULE_AUTHOR("Alexey Charkov <alchark@gmail.com"); | 172 | MODULE_AUTHOR("Alexey Charkov <alchark@gmail.com"); |
184 | MODULE_DESCRIPTION("Accelerators for raster operations using " | 173 | MODULE_DESCRIPTION("Accelerators for raster operations using " |
diff --git a/drivers/video/xilinxfb.c b/drivers/video/xilinxfb.c index fcb6cd90f64d..18084525402a 100644 --- a/drivers/video/xilinxfb.c +++ b/drivers/video/xilinxfb.c | |||
@@ -511,25 +511,7 @@ static struct platform_driver xilinxfb_of_driver = { | |||
511 | }, | 511 | }, |
512 | }; | 512 | }; |
513 | 513 | ||
514 | 514 | module_platform_driver(xilinxfb_of_driver); | |
515 | /* --------------------------------------------------------------------- | ||
516 | * Module setup and teardown | ||
517 | */ | ||
518 | |||
519 | static int __init | ||
520 | xilinxfb_init(void) | ||
521 | { | ||
522 | return platform_driver_register(&xilinxfb_of_driver); | ||
523 | } | ||
524 | |||
525 | static void __exit | ||
526 | xilinxfb_cleanup(void) | ||
527 | { | ||
528 | platform_driver_unregister(&xilinxfb_of_driver); | ||
529 | } | ||
530 | |||
531 | module_init(xilinxfb_init); | ||
532 | module_exit(xilinxfb_cleanup); | ||
533 | 515 | ||
534 | MODULE_AUTHOR("MontaVista Software, Inc. <source@mvista.com>"); | 516 | MODULE_AUTHOR("MontaVista Software, Inc. <source@mvista.com>"); |
535 | MODULE_DESCRIPTION("Xilinx TFT frame buffer driver"); | 517 | MODULE_DESCRIPTION("Xilinx TFT frame buffer driver"); |
diff --git a/include/linux/display.h b/include/linux/display.h deleted file mode 100644 index 3bf70d639728..000000000000 --- a/include/linux/display.h +++ /dev/null | |||
@@ -1,61 +0,0 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2006 James Simmons <jsimmons@infradead.org> | ||
3 | * | ||
4 | * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License as published by | ||
8 | * the Free Software Foundation; either version 2 of the License, or (at | ||
9 | * your option) any later version. | ||
10 | * | ||
11 | * This program is distributed in the hope that it will be useful, but | ||
12 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
14 | * General Public License for more details. | ||
15 | * | ||
16 | * You should have received a copy of the GNU General Public License along | ||
17 | * with this program; if not, write to the Free Software Foundation, Inc., | ||
18 | * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. | ||
19 | * | ||
20 | * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | ||
21 | */ | ||
22 | |||
23 | #ifndef _LINUX_DISPLAY_H | ||
24 | #define _LINUX_DISPLAY_H | ||
25 | |||
26 | #include <linux/device.h> | ||
27 | |||
28 | struct display_device; | ||
29 | |||
30 | /* This structure defines all the properties of a Display. */ | ||
31 | struct display_driver { | ||
32 | int (*set_contrast)(struct display_device *, unsigned int); | ||
33 | int (*get_contrast)(struct display_device *); | ||
34 | void (*suspend)(struct display_device *, pm_message_t state); | ||
35 | void (*resume)(struct display_device *); | ||
36 | int (*probe)(struct display_device *, void *); | ||
37 | int (*remove)(struct display_device *); | ||
38 | int max_contrast; | ||
39 | }; | ||
40 | |||
41 | struct display_device { | ||
42 | struct module *owner; /* Owner module */ | ||
43 | struct display_driver *driver; | ||
44 | struct device *parent; /* This is the parent */ | ||
45 | struct device *dev; /* This is this display device */ | ||
46 | struct mutex lock; | ||
47 | void *priv_data; | ||
48 | char type[16]; | ||
49 | char *name; | ||
50 | int idx; | ||
51 | }; | ||
52 | |||
53 | extern struct display_device *display_device_register(struct display_driver *driver, | ||
54 | struct device *dev, void *devdata); | ||
55 | extern void display_device_unregister(struct display_device *dev); | ||
56 | |||
57 | extern int probe_edid(struct display_device *dev, void *devdata); | ||
58 | |||
59 | #define to_display_device(obj) container_of(obj, struct display_device, class_dev) | ||
60 | |||
61 | #endif | ||
diff --git a/include/linux/fb.h b/include/linux/fb.h index 1d6836c498dd..c18122f40543 100644 --- a/include/linux/fb.h +++ b/include/linux/fb.h | |||
@@ -45,6 +45,7 @@ | |||
45 | #define FB_TYPE_INTERLEAVED_PLANES 2 /* Interleaved planes */ | 45 | #define FB_TYPE_INTERLEAVED_PLANES 2 /* Interleaved planes */ |
46 | #define FB_TYPE_TEXT 3 /* Text/attributes */ | 46 | #define FB_TYPE_TEXT 3 /* Text/attributes */ |
47 | #define FB_TYPE_VGA_PLANES 4 /* EGA/VGA planes */ | 47 | #define FB_TYPE_VGA_PLANES 4 /* EGA/VGA planes */ |
48 | #define FB_TYPE_FOURCC 5 /* Type identified by a V4L2 FOURCC */ | ||
48 | 49 | ||
49 | #define FB_AUX_TEXT_MDA 0 /* Monochrome text */ | 50 | #define FB_AUX_TEXT_MDA 0 /* Monochrome text */ |
50 | #define FB_AUX_TEXT_CGA 1 /* CGA/EGA/VGA Color text */ | 51 | #define FB_AUX_TEXT_CGA 1 /* CGA/EGA/VGA Color text */ |
@@ -69,6 +70,7 @@ | |||
69 | #define FB_VISUAL_PSEUDOCOLOR 3 /* Pseudo color (like atari) */ | 70 | #define FB_VISUAL_PSEUDOCOLOR 3 /* Pseudo color (like atari) */ |
70 | #define FB_VISUAL_DIRECTCOLOR 4 /* Direct color */ | 71 | #define FB_VISUAL_DIRECTCOLOR 4 /* Direct color */ |
71 | #define FB_VISUAL_STATIC_PSEUDOCOLOR 5 /* Pseudo color readonly */ | 72 | #define FB_VISUAL_STATIC_PSEUDOCOLOR 5 /* Pseudo color readonly */ |
73 | #define FB_VISUAL_FOURCC 6 /* Visual identified by a V4L2 FOURCC */ | ||
72 | 74 | ||
73 | #define FB_ACCEL_NONE 0 /* no hardware accelerator */ | 75 | #define FB_ACCEL_NONE 0 /* no hardware accelerator */ |
74 | #define FB_ACCEL_ATARIBLITT 1 /* Atari Blitter */ | 76 | #define FB_ACCEL_ATARIBLITT 1 /* Atari Blitter */ |
@@ -154,6 +156,8 @@ | |||
154 | 156 | ||
155 | #define FB_ACCEL_PUV3_UNIGFX 0xa0 /* PKUnity-v3 Unigfx */ | 157 | #define FB_ACCEL_PUV3_UNIGFX 0xa0 /* PKUnity-v3 Unigfx */ |
156 | 158 | ||
159 | #define FB_CAP_FOURCC 1 /* Device supports FOURCC-based formats */ | ||
160 | |||
157 | struct fb_fix_screeninfo { | 161 | struct fb_fix_screeninfo { |
158 | char id[16]; /* identification string eg "TT Builtin" */ | 162 | char id[16]; /* identification string eg "TT Builtin" */ |
159 | unsigned long smem_start; /* Start of frame buffer mem */ | 163 | unsigned long smem_start; /* Start of frame buffer mem */ |
@@ -171,7 +175,8 @@ struct fb_fix_screeninfo { | |||
171 | __u32 mmio_len; /* Length of Memory Mapped I/O */ | 175 | __u32 mmio_len; /* Length of Memory Mapped I/O */ |
172 | __u32 accel; /* Indicate to driver which */ | 176 | __u32 accel; /* Indicate to driver which */ |
173 | /* specific chip/card we have */ | 177 | /* specific chip/card we have */ |
174 | __u16 reserved[3]; /* Reserved for future compatibility */ | 178 | __u16 capabilities; /* see FB_CAP_* */ |
179 | __u16 reserved[2]; /* Reserved for future compatibility */ | ||
175 | }; | 180 | }; |
176 | 181 | ||
177 | /* Interpretation of offset for color fields: All offsets are from the right, | 182 | /* Interpretation of offset for color fields: All offsets are from the right, |
@@ -246,8 +251,8 @@ struct fb_var_screeninfo { | |||
246 | __u32 yoffset; /* resolution */ | 251 | __u32 yoffset; /* resolution */ |
247 | 252 | ||
248 | __u32 bits_per_pixel; /* guess what */ | 253 | __u32 bits_per_pixel; /* guess what */ |
249 | __u32 grayscale; /* != 0 Graylevels instead of colors */ | 254 | __u32 grayscale; /* 0 = color, 1 = grayscale, */ |
250 | 255 | /* >1 = FOURCC */ | |
251 | struct fb_bitfield red; /* bitfield in fb mem if true color, */ | 256 | struct fb_bitfield red; /* bitfield in fb mem if true color, */ |
252 | struct fb_bitfield green; /* else only length is significant */ | 257 | struct fb_bitfield green; /* else only length is significant */ |
253 | struct fb_bitfield blue; | 258 | struct fb_bitfield blue; |
@@ -273,7 +278,8 @@ struct fb_var_screeninfo { | |||
273 | __u32 sync; /* see FB_SYNC_* */ | 278 | __u32 sync; /* see FB_SYNC_* */ |
274 | __u32 vmode; /* see FB_VMODE_* */ | 279 | __u32 vmode; /* see FB_VMODE_* */ |
275 | __u32 rotate; /* angle we rotate counter clockwise */ | 280 | __u32 rotate; /* angle we rotate counter clockwise */ |
276 | __u32 reserved[5]; /* Reserved for future compatibility */ | 281 | __u32 colorspace; /* colorspace for FOURCC-based modes */ |
282 | __u32 reserved[4]; /* Reserved for future compatibility */ | ||
277 | }; | 283 | }; |
278 | 284 | ||
279 | struct fb_cmap { | 285 | struct fb_cmap { |
diff --git a/include/linux/videodev2.h b/include/linux/videodev2.h index 4b752d5ee80e..d2f74f8e3fe3 100644 --- a/include/linux/videodev2.h +++ b/include/linux/videodev2.h | |||
@@ -343,6 +343,8 @@ struct v4l2_pix_format { | |||
343 | #define V4L2_PIX_FMT_NV21 v4l2_fourcc('N', 'V', '2', '1') /* 12 Y/CrCb 4:2:0 */ | 343 | #define V4L2_PIX_FMT_NV21 v4l2_fourcc('N', 'V', '2', '1') /* 12 Y/CrCb 4:2:0 */ |
344 | #define V4L2_PIX_FMT_NV16 v4l2_fourcc('N', 'V', '1', '6') /* 16 Y/CbCr 4:2:2 */ | 344 | #define V4L2_PIX_FMT_NV16 v4l2_fourcc('N', 'V', '1', '6') /* 16 Y/CbCr 4:2:2 */ |
345 | #define V4L2_PIX_FMT_NV61 v4l2_fourcc('N', 'V', '6', '1') /* 16 Y/CrCb 4:2:2 */ | 345 | #define V4L2_PIX_FMT_NV61 v4l2_fourcc('N', 'V', '6', '1') /* 16 Y/CrCb 4:2:2 */ |
346 | #define V4L2_PIX_FMT_NV24 v4l2_fourcc('N', 'V', '2', '4') /* 24 Y/CbCr 4:4:4 */ | ||
347 | #define V4L2_PIX_FMT_NV42 v4l2_fourcc('N', 'V', '4', '2') /* 24 Y/CrCb 4:4:4 */ | ||
346 | 348 | ||
347 | /* two non contiguous planes - one Y, one Cr + Cb interleaved */ | 349 | /* two non contiguous planes - one Y, one Cr + Cb interleaved */ |
348 | #define V4L2_PIX_FMT_NV12M v4l2_fourcc('N', 'M', '1', '2') /* 12 Y/CbCr 4:2:0 */ | 350 | #define V4L2_PIX_FMT_NV12M v4l2_fourcc('N', 'M', '1', '2') /* 12 Y/CbCr 4:2:0 */ |
diff --git a/include/linux/zorro_ids.h b/include/linux/zorro_ids.h index 7e749088910d..74bc53bcfdcf 100644 --- a/include/linux/zorro_ids.h +++ b/include/linux/zorro_ids.h | |||
@@ -360,8 +360,8 @@ | |||
360 | #define ZORRO_PROD_VILLAGE_TRONIC_PICASSO_II_II_PLUS_RAM ZORRO_ID(VILLAGE_TRONIC, 0x0B, 0) | 360 | #define ZORRO_PROD_VILLAGE_TRONIC_PICASSO_II_II_PLUS_RAM ZORRO_ID(VILLAGE_TRONIC, 0x0B, 0) |
361 | #define ZORRO_PROD_VILLAGE_TRONIC_PICASSO_II_II_PLUS_REG ZORRO_ID(VILLAGE_TRONIC, 0x0C, 0) | 361 | #define ZORRO_PROD_VILLAGE_TRONIC_PICASSO_II_II_PLUS_REG ZORRO_ID(VILLAGE_TRONIC, 0x0C, 0) |
362 | #define ZORRO_PROD_VILLAGE_TRONIC_PICASSO_II_II_PLUS_SEGMENTED_MODE ZORRO_ID(VILLAGE_TRONIC, 0x0D, 0) | 362 | #define ZORRO_PROD_VILLAGE_TRONIC_PICASSO_II_II_PLUS_SEGMENTED_MODE ZORRO_ID(VILLAGE_TRONIC, 0x0D, 0) |
363 | #define ZORRO_PROD_VILLAGE_TRONIC_PICASSO_IV_Z2_MEM1 ZORRO_ID(VILLAGE_TRONIC, 0x15, 0) | 363 | #define ZORRO_PROD_VILLAGE_TRONIC_PICASSO_IV_Z2_RAM1 ZORRO_ID(VILLAGE_TRONIC, 0x15, 0) |
364 | #define ZORRO_PROD_VILLAGE_TRONIC_PICASSO_IV_Z2_MEM2 ZORRO_ID(VILLAGE_TRONIC, 0x16, 0) | 364 | #define ZORRO_PROD_VILLAGE_TRONIC_PICASSO_IV_Z2_RAM2 ZORRO_ID(VILLAGE_TRONIC, 0x16, 0) |
365 | #define ZORRO_PROD_VILLAGE_TRONIC_PICASSO_IV_Z2_REG ZORRO_ID(VILLAGE_TRONIC, 0x17, 0) | 365 | #define ZORRO_PROD_VILLAGE_TRONIC_PICASSO_IV_Z2_REG ZORRO_ID(VILLAGE_TRONIC, 0x17, 0) |
366 | #define ZORRO_PROD_VILLAGE_TRONIC_PICASSO_IV_Z3 ZORRO_ID(VILLAGE_TRONIC, 0x18, 0) | 366 | #define ZORRO_PROD_VILLAGE_TRONIC_PICASSO_IV_Z3 ZORRO_ID(VILLAGE_TRONIC, 0x18, 0) |
367 | #define ZORRO_PROD_VILLAGE_TRONIC_ARIADNE ZORRO_ID(VILLAGE_TRONIC, 0xC9, 0) | 367 | #define ZORRO_PROD_VILLAGE_TRONIC_ARIADNE ZORRO_ID(VILLAGE_TRONIC, 0xC9, 0) |
diff --git a/include/video/omapdss.h b/include/video/omapdss.h index 378c7ed6760b..062b3b24ff10 100644 --- a/include/video/omapdss.h +++ b/include/video/omapdss.h | |||
@@ -200,6 +200,10 @@ enum omap_dss_clk_source { | |||
200 | OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DSI, /* OMAP4: PLL2_CLK2 */ | 200 | OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DSI, /* OMAP4: PLL2_CLK2 */ |
201 | }; | 201 | }; |
202 | 202 | ||
203 | enum omap_hdmi_flags { | ||
204 | OMAP_HDMI_SDA_SCL_EXTERNAL_PULLUP = 1 << 0, | ||
205 | }; | ||
206 | |||
203 | /* RFBI */ | 207 | /* RFBI */ |
204 | 208 | ||
205 | struct rfbi_timings { | 209 | struct rfbi_timings { |
@@ -294,8 +298,8 @@ int dsi_vc_set_max_rx_packet_size(struct omap_dss_device *dssdev, int channel, | |||
294 | u16 len); | 298 | u16 len); |
295 | int dsi_vc_send_null(struct omap_dss_device *dssdev, int channel); | 299 | int dsi_vc_send_null(struct omap_dss_device *dssdev, int channel); |
296 | int dsi_vc_send_bta_sync(struct omap_dss_device *dssdev, int channel); | 300 | int dsi_vc_send_bta_sync(struct omap_dss_device *dssdev, int channel); |
297 | int dsi_video_mode_enable(struct omap_dss_device *dssdev, int channel); | 301 | int dsi_enable_video_output(struct omap_dss_device *dssdev, int channel); |
298 | void dsi_video_mode_disable(struct omap_dss_device *dssdev, int channel); | 302 | void dsi_disable_video_output(struct omap_dss_device *dssdev, int channel); |
299 | 303 | ||
300 | /* Board specific data */ | 304 | /* Board specific data */ |
301 | struct omap_dss_board_info { | 305 | struct omap_dss_board_info { |
@@ -309,6 +313,8 @@ struct omap_dss_board_info { | |||
309 | 313 | ||
310 | /* Init with the board info */ | 314 | /* Init with the board info */ |
311 | extern int omap_display_init(struct omap_dss_board_info *board_data); | 315 | extern int omap_display_init(struct omap_dss_board_info *board_data); |
316 | /* HDMI mux init*/ | ||
317 | extern int omap_hdmi_init(enum omap_hdmi_flags flags); | ||
312 | 318 | ||
313 | struct omap_display_platform_data { | 319 | struct omap_display_platform_data { |
314 | struct omap_dss_board_info *board_data; | 320 | struct omap_dss_board_info *board_data; |
@@ -352,8 +358,6 @@ struct omap_dss_cpr_coefs { | |||
352 | }; | 358 | }; |
353 | 359 | ||
354 | struct omap_overlay_info { | 360 | struct omap_overlay_info { |
355 | bool enabled; | ||
356 | |||
357 | u32 paddr; | 361 | u32 paddr; |
358 | u32 p_uv_addr; /* for NV12 format */ | 362 | u32 p_uv_addr; /* for NV12 format */ |
359 | u16 screen_width; | 363 | u16 screen_width; |
@@ -385,11 +389,21 @@ struct omap_overlay { | |||
385 | 389 | ||
386 | /* dynamic fields */ | 390 | /* dynamic fields */ |
387 | struct omap_overlay_manager *manager; | 391 | struct omap_overlay_manager *manager; |
388 | struct omap_overlay_info info; | ||
389 | 392 | ||
390 | bool manager_changed; | 393 | /* |
391 | /* if true, info has been changed, but not applied() yet */ | 394 | * The following functions do not block: |
392 | bool info_dirty; | 395 | * |
396 | * is_enabled | ||
397 | * set_overlay_info | ||
398 | * get_overlay_info | ||
399 | * | ||
400 | * The rest of the functions may block and cannot be called from | ||
401 | * interrupt context | ||
402 | */ | ||
403 | |||
404 | int (*enable)(struct omap_overlay *ovl); | ||
405 | int (*disable)(struct omap_overlay *ovl); | ||
406 | bool (*is_enabled)(struct omap_overlay *ovl); | ||
393 | 407 | ||
394 | int (*set_manager)(struct omap_overlay *ovl, | 408 | int (*set_manager)(struct omap_overlay *ovl, |
395 | struct omap_overlay_manager *mgr); | 409 | struct omap_overlay_manager *mgr); |
@@ -418,23 +432,27 @@ struct omap_overlay_manager_info { | |||
418 | 432 | ||
419 | struct omap_overlay_manager { | 433 | struct omap_overlay_manager { |
420 | struct kobject kobj; | 434 | struct kobject kobj; |
421 | struct list_head list; | ||
422 | 435 | ||
423 | /* static fields */ | 436 | /* static fields */ |
424 | const char *name; | 437 | const char *name; |
425 | enum omap_channel id; | 438 | enum omap_channel id; |
426 | enum omap_overlay_manager_caps caps; | 439 | enum omap_overlay_manager_caps caps; |
427 | int num_overlays; | 440 | struct list_head overlays; |
428 | struct omap_overlay **overlays; | ||
429 | enum omap_display_type supported_displays; | 441 | enum omap_display_type supported_displays; |
430 | 442 | ||
431 | /* dynamic fields */ | 443 | /* dynamic fields */ |
432 | struct omap_dss_device *device; | 444 | struct omap_dss_device *device; |
433 | struct omap_overlay_manager_info info; | ||
434 | 445 | ||
435 | bool device_changed; | 446 | /* |
436 | /* if true, info has been changed but not applied() yet */ | 447 | * The following functions do not block: |
437 | bool info_dirty; | 448 | * |
449 | * set_manager_info | ||
450 | * get_manager_info | ||
451 | * apply | ||
452 | * | ||
453 | * The rest of the functions may block and cannot be called from | ||
454 | * interrupt context | ||
455 | */ | ||
438 | 456 | ||
439 | int (*set_device)(struct omap_overlay_manager *mgr, | 457 | int (*set_device)(struct omap_overlay_manager *mgr, |
440 | struct omap_dss_device *dssdev); | 458 | struct omap_dss_device *dssdev); |
@@ -448,9 +466,6 @@ struct omap_overlay_manager { | |||
448 | int (*apply)(struct omap_overlay_manager *mgr); | 466 | int (*apply)(struct omap_overlay_manager *mgr); |
449 | int (*wait_for_go)(struct omap_overlay_manager *mgr); | 467 | int (*wait_for_go)(struct omap_overlay_manager *mgr); |
450 | int (*wait_for_vsync)(struct omap_overlay_manager *mgr); | 468 | int (*wait_for_vsync)(struct omap_overlay_manager *mgr); |
451 | |||
452 | int (*enable)(struct omap_overlay_manager *mgr); | ||
453 | int (*disable)(struct omap_overlay_manager *mgr); | ||
454 | }; | 469 | }; |
455 | 470 | ||
456 | struct omap_dss_device { | 471 | struct omap_dss_device { |
@@ -662,12 +677,7 @@ void omapdss_dsi_vc_enable_hs(struct omap_dss_device *dssdev, int channel, | |||
662 | bool enable); | 677 | bool enable); |
663 | int omapdss_dsi_enable_te(struct omap_dss_device *dssdev, bool enable); | 678 | int omapdss_dsi_enable_te(struct omap_dss_device *dssdev, bool enable); |
664 | 679 | ||
665 | int omap_dsi_prepare_update(struct omap_dss_device *dssdev, | 680 | int omap_dsi_update(struct omap_dss_device *dssdev, int channel, |
666 | u16 *x, u16 *y, u16 *w, u16 *h, | ||
667 | bool enlarge_update_area); | ||
668 | int omap_dsi_update(struct omap_dss_device *dssdev, | ||
669 | int channel, | ||
670 | u16 x, u16 y, u16 w, u16 h, | ||
671 | void (*callback)(int, void *), void *data); | 681 | void (*callback)(int, void *), void *data); |
672 | int omap_dsi_request_vc(struct omap_dss_device *dssdev, int *channel); | 682 | int omap_dsi_request_vc(struct omap_dss_device *dssdev, int *channel); |
673 | int omap_dsi_set_vc_id(struct omap_dss_device *dssdev, int channel, int vc_id); | 683 | int omap_dsi_set_vc_id(struct omap_dss_device *dssdev, int channel, int vc_id); |
diff --git a/include/video/sh_mipi_dsi.h b/include/video/sh_mipi_dsi.h index 6cb95c977de9..434d56b4a1a5 100644 --- a/include/video/sh_mipi_dsi.h +++ b/include/video/sh_mipi_dsi.h | |||
@@ -28,14 +28,33 @@ enum sh_mipi_dsi_data_fmt { | |||
28 | struct sh_mobile_lcdc_chan_cfg; | 28 | struct sh_mobile_lcdc_chan_cfg; |
29 | 29 | ||
30 | #define SH_MIPI_DSI_HSABM (1 << 0) | 30 | #define SH_MIPI_DSI_HSABM (1 << 0) |
31 | #define SH_MIPI_DSI_HSPBM (1 << 1) | 31 | #define SH_MIPI_DSI_HBPBM (1 << 1) |
32 | #define SH_MIPI_DSI_HFPBM (1 << 2) | ||
33 | #define SH_MIPI_DSI_BL2E (1 << 3) | ||
34 | #define SH_MIPI_DSI_VSEE (1 << 4) | ||
35 | #define SH_MIPI_DSI_HSEE (1 << 5) | ||
36 | #define SH_MIPI_DSI_HSAE (1 << 6) | ||
37 | |||
38 | #define SH_MIPI_DSI_HSbyteCLK (1 << 24) | ||
39 | #define SH_MIPI_DSI_HS6divCLK (1 << 25) | ||
40 | #define SH_MIPI_DSI_HS4divCLK (1 << 26) | ||
41 | |||
42 | #define SH_MIPI_DSI_SYNC_PULSES_MODE (SH_MIPI_DSI_VSEE | \ | ||
43 | SH_MIPI_DSI_HSEE | \ | ||
44 | SH_MIPI_DSI_HSAE) | ||
45 | #define SH_MIPI_DSI_SYNC_EVENTS_MODE (0) | ||
46 | #define SH_MIPI_DSI_SYNC_BURST_MODE (SH_MIPI_DSI_BL2E) | ||
32 | 47 | ||
33 | struct sh_mipi_dsi_info { | 48 | struct sh_mipi_dsi_info { |
34 | enum sh_mipi_dsi_data_fmt data_format; | 49 | enum sh_mipi_dsi_data_fmt data_format; |
35 | struct sh_mobile_lcdc_chan_cfg *lcd_chan; | 50 | struct sh_mobile_lcdc_chan_cfg *lcd_chan; |
51 | int lane; | ||
36 | unsigned long flags; | 52 | unsigned long flags; |
37 | u32 clksrc; | 53 | u32 clksrc; |
38 | unsigned int vsynw_offset; | 54 | unsigned int vsynw_offset; |
55 | int (*set_dot_clock)(struct platform_device *pdev, | ||
56 | void __iomem *base, | ||
57 | int enable); | ||
39 | }; | 58 | }; |
40 | 59 | ||
41 | #endif | 60 | #endif |
diff --git a/include/video/sh_mobile_lcdc.h b/include/video/sh_mobile_lcdc.h index 8101b726b48a..fe30b759c51e 100644 --- a/include/video/sh_mobile_lcdc.h +++ b/include/video/sh_mobile_lcdc.h | |||
@@ -174,7 +174,8 @@ struct sh_mobile_lcdc_bl_info { | |||
174 | 174 | ||
175 | struct sh_mobile_lcdc_chan_cfg { | 175 | struct sh_mobile_lcdc_chan_cfg { |
176 | int chan; | 176 | int chan; |
177 | int bpp; | 177 | int fourcc; |
178 | int colorspace; | ||
178 | int interface_type; /* selects RGBn or SYSn I/F, see above */ | 179 | int interface_type; /* selects RGBn or SYSn I/F, see above */ |
179 | int clock_divider; | 180 | int clock_divider; |
180 | unsigned long flags; /* LCDC_FLAGS_... */ | 181 | unsigned long flags; /* LCDC_FLAGS_... */ |
@@ -184,7 +185,6 @@ struct sh_mobile_lcdc_chan_cfg { | |||
184 | struct sh_mobile_lcdc_board_cfg board_cfg; | 185 | struct sh_mobile_lcdc_board_cfg board_cfg; |
185 | struct sh_mobile_lcdc_bl_info bl_info; | 186 | struct sh_mobile_lcdc_bl_info bl_info; |
186 | struct sh_mobile_lcdc_sys_bus_cfg sys_bus_cfg; /* only for SYSn I/F */ | 187 | struct sh_mobile_lcdc_sys_bus_cfg sys_bus_cfg; /* only for SYSn I/F */ |
187 | int nonstd; | ||
188 | struct sh_mobile_meram_cfg *meram_cfg; | 188 | struct sh_mobile_meram_cfg *meram_cfg; |
189 | }; | 189 | }; |
190 | 190 | ||