diff options
Diffstat (limited to 'drivers/video/via/hw.c')
-rw-r--r-- | drivers/video/via/hw.c | 630 |
1 files changed, 210 insertions, 420 deletions
diff --git a/drivers/video/via/hw.c b/drivers/video/via/hw.c index dc4c778877ce..47b13535ed2b 100644 --- a/drivers/video/via/hw.c +++ b/drivers/video/via/hw.c | |||
@@ -20,274 +20,84 @@ | |||
20 | */ | 20 | */ |
21 | 21 | ||
22 | #include <linux/via-core.h> | 22 | #include <linux/via-core.h> |
23 | #include <asm/olpc.h> | ||
23 | #include "global.h" | 24 | #include "global.h" |
24 | 25 | #include "via_clock.h" | |
25 | static struct pll_config cle266_pll_config[] = { | 26 | |
26 | {19, 4, 0}, | 27 | static struct pll_limit cle266_pll_limits[] = { |
27 | {26, 5, 0}, | 28 | {19, 19, 4, 0}, |
28 | {28, 5, 0}, | 29 | {26, 102, 5, 0}, |
29 | {31, 5, 0}, | 30 | {53, 112, 6, 0}, |
30 | {33, 5, 0}, | 31 | {41, 100, 7, 0}, |
31 | {55, 5, 0}, | 32 | {83, 108, 8, 0}, |
32 | {102, 5, 0}, | 33 | {87, 118, 9, 0}, |
33 | {53, 6, 0}, | 34 | {95, 115, 12, 0}, |
34 | {92, 6, 0}, | 35 | {108, 108, 13, 0}, |
35 | {98, 6, 0}, | 36 | {83, 83, 17, 0}, |
36 | {112, 6, 0}, | 37 | {67, 98, 20, 0}, |
37 | {41, 7, 0}, | 38 | {121, 121, 24, 0}, |
38 | {60, 7, 0}, | 39 | {99, 99, 29, 0}, |
39 | {99, 7, 0}, | 40 | {33, 33, 3, 1}, |
40 | {100, 7, 0}, | 41 | {15, 23, 4, 1}, |
41 | {83, 8, 0}, | 42 | {37, 121, 5, 1}, |
42 | {86, 8, 0}, | 43 | {82, 82, 6, 1}, |
43 | {108, 8, 0}, | 44 | {31, 84, 7, 1}, |
44 | {87, 9, 0}, | 45 | {83, 83, 8, 1}, |
45 | {118, 9, 0}, | 46 | {76, 127, 9, 1}, |
46 | {95, 12, 0}, | 47 | {33, 121, 4, 2}, |
47 | {115, 12, 0}, | 48 | {91, 118, 5, 2}, |
48 | {108, 13, 0}, | 49 | {83, 109, 6, 2}, |
49 | {83, 17, 0}, | 50 | {90, 90, 7, 2}, |
50 | {67, 20, 0}, | 51 | {93, 93, 2, 3}, |
51 | {86, 20, 0}, | 52 | {53, 53, 3, 3}, |
52 | {98, 20, 0}, | 53 | {73, 117, 4, 3}, |
53 | {121, 24, 0}, | 54 | {101, 127, 5, 3}, |
54 | {99, 29, 0}, | 55 | {99, 99, 7, 3} |
55 | {33, 3, 1}, | ||
56 | {15, 4, 1}, | ||
57 | {23, 4, 1}, | ||
58 | {37, 5, 1}, | ||
59 | {83, 5, 1}, | ||
60 | {85, 5, 1}, | ||
61 | {94, 5, 1}, | ||
62 | {103, 5, 1}, | ||
63 | {109, 5, 1}, | ||
64 | {113, 5, 1}, | ||
65 | {121, 5, 1}, | ||
66 | {82, 6, 1}, | ||
67 | {31, 7, 1}, | ||
68 | {55, 7, 1}, | ||
69 | {84, 7, 1}, | ||
70 | {83, 8, 1}, | ||
71 | {76, 9, 1}, | ||
72 | {127, 9, 1}, | ||
73 | {33, 4, 2}, | ||
74 | {75, 4, 2}, | ||
75 | {119, 4, 2}, | ||
76 | {121, 4, 2}, | ||
77 | {91, 5, 2}, | ||
78 | {118, 5, 2}, | ||
79 | {83, 6, 2}, | ||
80 | {109, 6, 2}, | ||
81 | {90, 7, 2}, | ||
82 | {93, 2, 3}, | ||
83 | {53, 3, 3}, | ||
84 | {73, 4, 3}, | ||
85 | {89, 4, 3}, | ||
86 | {105, 4, 3}, | ||
87 | {117, 4, 3}, | ||
88 | {101, 5, 3}, | ||
89 | {121, 5, 3}, | ||
90 | {127, 5, 3}, | ||
91 | {99, 7, 3} | ||
92 | }; | 56 | }; |
93 | 57 | ||
94 | static struct pll_config k800_pll_config[] = { | 58 | static struct pll_limit k800_pll_limits[] = { |
95 | {22, 2, 0}, | 59 | {22, 22, 2, 0}, |
96 | {28, 3, 0}, | 60 | {28, 28, 3, 0}, |
97 | {81, 3, 1}, | 61 | {81, 112, 3, 1}, |
98 | {85, 3, 1}, | 62 | {86, 166, 4, 1}, |
99 | {98, 3, 1}, | 63 | {109, 153, 5, 1}, |
100 | {112, 3, 1}, | 64 | {66, 116, 3, 2}, |
101 | {86, 4, 1}, | 65 | {93, 137, 4, 2}, |
102 | {166, 4, 1}, | 66 | {117, 208, 5, 2}, |
103 | {109, 5, 1}, | 67 | {30, 30, 2, 3}, |
104 | {113, 5, 1}, | 68 | {69, 125, 3, 3}, |
105 | {121, 5, 1}, | 69 | {89, 161, 4, 3}, |
106 | {131, 5, 1}, | 70 | {121, 208, 5, 3}, |
107 | {143, 5, 1}, | 71 | {66, 66, 2, 4}, |
108 | {153, 5, 1}, | 72 | {85, 85, 3, 4}, |
109 | {66, 3, 2}, | 73 | {141, 161, 4, 4}, |
110 | {68, 3, 2}, | 74 | {177, 177, 5, 4} |
111 | {95, 3, 2}, | ||
112 | {106, 3, 2}, | ||
113 | {116, 3, 2}, | ||
114 | {93, 4, 2}, | ||
115 | {119, 4, 2}, | ||
116 | {121, 4, 2}, | ||
117 | {133, 4, 2}, | ||
118 | {137, 4, 2}, | ||
119 | {117, 5, 2}, | ||
120 | {118, 5, 2}, | ||
121 | {120, 5, 2}, | ||
122 | {124, 5, 2}, | ||
123 | {132, 5, 2}, | ||
124 | {137, 5, 2}, | ||
125 | {141, 5, 2}, | ||
126 | {166, 5, 2}, | ||
127 | {170, 5, 2}, | ||
128 | {191, 5, 2}, | ||
129 | {206, 5, 2}, | ||
130 | {208, 5, 2}, | ||
131 | {30, 2, 3}, | ||
132 | {69, 3, 3}, | ||
133 | {82, 3, 3}, | ||
134 | {83, 3, 3}, | ||
135 | {109, 3, 3}, | ||
136 | {114, 3, 3}, | ||
137 | {125, 3, 3}, | ||
138 | {89, 4, 3}, | ||
139 | {103, 4, 3}, | ||
140 | {117, 4, 3}, | ||
141 | {126, 4, 3}, | ||
142 | {150, 4, 3}, | ||
143 | {161, 4, 3}, | ||
144 | {121, 5, 3}, | ||
145 | {127, 5, 3}, | ||
146 | {131, 5, 3}, | ||
147 | {134, 5, 3}, | ||
148 | {148, 5, 3}, | ||
149 | {169, 5, 3}, | ||
150 | {172, 5, 3}, | ||
151 | {182, 5, 3}, | ||
152 | {195, 5, 3}, | ||
153 | {196, 5, 3}, | ||
154 | {208, 5, 3}, | ||
155 | {66, 2, 4}, | ||
156 | {85, 3, 4}, | ||
157 | {141, 4, 4}, | ||
158 | {146, 4, 4}, | ||
159 | {161, 4, 4}, | ||
160 | {177, 5, 4} | ||
161 | }; | 75 | }; |
162 | 76 | ||
163 | static struct pll_config cx700_pll_config[] = { | 77 | static struct pll_limit cx700_pll_limits[] = { |
164 | {98, 3, 1}, | 78 | {98, 98, 3, 1}, |
165 | {86, 4, 1}, | 79 | {86, 86, 4, 1}, |
166 | {109, 5, 1}, | 80 | {109, 208, 5, 1}, |
167 | {110, 5, 1}, | 81 | {68, 68, 2, 2}, |
168 | {113, 5, 1}, | 82 | {95, 116, 3, 2}, |
169 | {121, 5, 1}, | 83 | {93, 166, 4, 2}, |
170 | {131, 5, 1}, | 84 | {110, 206, 5, 2}, |
171 | {135, 5, 1}, | 85 | {174, 174, 7, 2}, |
172 | {142, 5, 1}, | 86 | {82, 109, 3, 3}, |
173 | {143, 5, 1}, | 87 | {117, 161, 4, 3}, |
174 | {153, 5, 1}, | 88 | {112, 208, 5, 3}, |
175 | {187, 5, 1}, | 89 | {141, 202, 5, 4} |
176 | {208, 5, 1}, | ||
177 | {68, 2, 2}, | ||
178 | {95, 3, 2}, | ||
179 | {116, 3, 2}, | ||
180 | {93, 4, 2}, | ||
181 | {119, 4, 2}, | ||
182 | {133, 4, 2}, | ||
183 | {137, 4, 2}, | ||
184 | {151, 4, 2}, | ||
185 | {166, 4, 2}, | ||
186 | {110, 5, 2}, | ||
187 | {112, 5, 2}, | ||
188 | {117, 5, 2}, | ||
189 | {118, 5, 2}, | ||
190 | {120, 5, 2}, | ||
191 | {132, 5, 2}, | ||
192 | {137, 5, 2}, | ||
193 | {141, 5, 2}, | ||
194 | {151, 5, 2}, | ||
195 | {166, 5, 2}, | ||
196 | {175, 5, 2}, | ||
197 | {191, 5, 2}, | ||
198 | {206, 5, 2}, | ||
199 | {174, 7, 2}, | ||
200 | {82, 3, 3}, | ||
201 | {109, 3, 3}, | ||
202 | {117, 4, 3}, | ||
203 | {150, 4, 3}, | ||
204 | {161, 4, 3}, | ||
205 | {112, 5, 3}, | ||
206 | {115, 5, 3}, | ||
207 | {121, 5, 3}, | ||
208 | {127, 5, 3}, | ||
209 | {129, 5, 3}, | ||
210 | {131, 5, 3}, | ||
211 | {134, 5, 3}, | ||
212 | {138, 5, 3}, | ||
213 | {148, 5, 3}, | ||
214 | {157, 5, 3}, | ||
215 | {169, 5, 3}, | ||
216 | {172, 5, 3}, | ||
217 | {190, 5, 3}, | ||
218 | {195, 5, 3}, | ||
219 | {196, 5, 3}, | ||
220 | {208, 5, 3}, | ||
221 | {141, 5, 4}, | ||
222 | {150, 5, 4}, | ||
223 | {166, 5, 4}, | ||
224 | {176, 5, 4}, | ||
225 | {177, 5, 4}, | ||
226 | {183, 5, 4}, | ||
227 | {202, 5, 4} | ||
228 | }; | 90 | }; |
229 | 91 | ||
230 | static struct pll_config vx855_pll_config[] = { | 92 | static struct pll_limit vx855_pll_limits[] = { |
231 | {86, 4, 1}, | 93 | {86, 86, 4, 1}, |
232 | {108, 5, 1}, | 94 | {108, 208, 5, 1}, |
233 | {110, 5, 1}, | 95 | {110, 208, 5, 2}, |
234 | {113, 5, 1}, | 96 | {83, 112, 3, 3}, |
235 | {121, 5, 1}, | 97 | {103, 161, 4, 3}, |
236 | {131, 5, 1}, | 98 | {112, 209, 5, 3}, |
237 | {135, 5, 1}, | 99 | {142, 161, 4, 4}, |
238 | {142, 5, 1}, | 100 | {141, 176, 5, 4} |
239 | {143, 5, 1}, | ||
240 | {153, 5, 1}, | ||
241 | {164, 5, 1}, | ||
242 | {187, 5, 1}, | ||
243 | {208, 5, 1}, | ||
244 | {110, 5, 2}, | ||
245 | {112, 5, 2}, | ||
246 | {117, 5, 2}, | ||
247 | {118, 5, 2}, | ||
248 | {124, 5, 2}, | ||
249 | {132, 5, 2}, | ||
250 | {137, 5, 2}, | ||
251 | {141, 5, 2}, | ||
252 | {149, 5, 2}, | ||
253 | {151, 5, 2}, | ||
254 | {159, 5, 2}, | ||
255 | {166, 5, 2}, | ||
256 | {167, 5, 2}, | ||
257 | {172, 5, 2}, | ||
258 | {189, 5, 2}, | ||
259 | {191, 5, 2}, | ||
260 | {194, 5, 2}, | ||
261 | {206, 5, 2}, | ||
262 | {208, 5, 2}, | ||
263 | {83, 3, 3}, | ||
264 | {88, 3, 3}, | ||
265 | {109, 3, 3}, | ||
266 | {112, 3, 3}, | ||
267 | {103, 4, 3}, | ||
268 | {105, 4, 3}, | ||
269 | {161, 4, 3}, | ||
270 | {112, 5, 3}, | ||
271 | {115, 5, 3}, | ||
272 | {121, 5, 3}, | ||
273 | {127, 5, 3}, | ||
274 | {134, 5, 3}, | ||
275 | {137, 5, 3}, | ||
276 | {148, 5, 3}, | ||
277 | {157, 5, 3}, | ||
278 | {169, 5, 3}, | ||
279 | {172, 5, 3}, | ||
280 | {182, 5, 3}, | ||
281 | {191, 5, 3}, | ||
282 | {195, 5, 3}, | ||
283 | {209, 5, 3}, | ||
284 | {142, 4, 4}, | ||
285 | {146, 4, 4}, | ||
286 | {161, 4, 4}, | ||
287 | {141, 5, 4}, | ||
288 | {150, 5, 4}, | ||
289 | {165, 5, 4}, | ||
290 | {176, 5, 4} | ||
291 | }; | 101 | }; |
292 | 102 | ||
293 | /* according to VIA Technologies these values are based on experiment */ | 103 | /* according to VIA Technologies these values are based on experiment */ |
@@ -308,6 +118,42 @@ static struct io_reg scaling_parameters[] = { | |||
308 | {VIACR, CR87, 0xFF, 0x1F}, /* LCD Scaling Parameter 14 */ | 118 | {VIACR, CR87, 0xFF, 0x1F}, /* LCD Scaling Parameter 14 */ |
309 | }; | 119 | }; |
310 | 120 | ||
121 | static struct io_reg common_vga[] = { | ||
122 | {VIACR, CR07, 0x10, 0x10}, /* [0] vertical total (bit 8) | ||
123 | [1] vertical display end (bit 8) | ||
124 | [2] vertical retrace start (bit 8) | ||
125 | [3] start vertical blanking (bit 8) | ||
126 | [4] line compare (bit 8) | ||
127 | [5] vertical total (bit 9) | ||
128 | [6] vertical display end (bit 9) | ||
129 | [7] vertical retrace start (bit 9) */ | ||
130 | {VIACR, CR08, 0xFF, 0x00}, /* [0-4] preset row scan | ||
131 | [5-6] byte panning */ | ||
132 | {VIACR, CR09, 0xDF, 0x40}, /* [0-4] max scan line | ||
133 | [5] start vertical blanking (bit 9) | ||
134 | [6] line compare (bit 9) | ||
135 | [7] scan doubling */ | ||
136 | {VIACR, CR0A, 0xFF, 0x1E}, /* [0-4] cursor start | ||
137 | [5] cursor disable */ | ||
138 | {VIACR, CR0B, 0xFF, 0x00}, /* [0-4] cursor end | ||
139 | [5-6] cursor skew */ | ||
140 | {VIACR, CR0E, 0xFF, 0x00}, /* [0-7] cursor location (high) */ | ||
141 | {VIACR, CR0F, 0xFF, 0x00}, /* [0-7] cursor location (low) */ | ||
142 | {VIACR, CR11, 0xF0, 0x80}, /* [0-3] vertical retrace end | ||
143 | [6] memory refresh bandwidth | ||
144 | [7] CRTC register protect enable */ | ||
145 | {VIACR, CR14, 0xFF, 0x00}, /* [0-4] underline location | ||
146 | [5] divide memory address clock by 4 | ||
147 | [6] double word addressing */ | ||
148 | {VIACR, CR17, 0xFF, 0x63}, /* [0-1] mapping of display address 13-14 | ||
149 | [2] divide scan line clock by 2 | ||
150 | [3] divide memory address clock by 2 | ||
151 | [5] address wrap | ||
152 | [6] byte mode select | ||
153 | [7] sync enable */ | ||
154 | {VIACR, CR18, 0xFF, 0xFF}, /* [0-7] line compare */ | ||
155 | }; | ||
156 | |||
311 | static struct fifo_depth_select display_fifo_depth_reg = { | 157 | static struct fifo_depth_select display_fifo_depth_reg = { |
312 | /* IGA1 FIFO Depth_Select */ | 158 | /* IGA1 FIFO Depth_Select */ |
313 | {IGA1_FIFO_DEPTH_SELECT_REG_NUM, {{SR17, 0, 7} } }, | 159 | {IGA1_FIFO_DEPTH_SELECT_REG_NUM, {{SR17, 0, 7} } }, |
@@ -676,6 +522,9 @@ static struct via_device_mapping device_mapping[] = { | |||
676 | {VIA_LVDS2, "LVDS2"} | 522 | {VIA_LVDS2, "LVDS2"} |
677 | }; | 523 | }; |
678 | 524 | ||
525 | /* structure with function pointers to support clock control */ | ||
526 | static struct via_clock clock; | ||
527 | |||
679 | static void load_fix_bit_crtc_reg(void); | 528 | static void load_fix_bit_crtc_reg(void); |
680 | static void __devinit init_gfx_chip_info(int chip_type); | 529 | static void __devinit init_gfx_chip_info(int chip_type); |
681 | static void __devinit init_tmds_chip_info(void); | 530 | static void __devinit init_tmds_chip_info(void); |
@@ -770,13 +619,14 @@ static u32 get_lcd_devices(int output_interface) | |||
770 | /*Set IGA path for each device*/ | 619 | /*Set IGA path for each device*/ |
771 | void viafb_set_iga_path(void) | 620 | void viafb_set_iga_path(void) |
772 | { | 621 | { |
622 | int crt_iga_path = 0; | ||
773 | 623 | ||
774 | if (viafb_SAMM_ON == 1) { | 624 | if (viafb_SAMM_ON == 1) { |
775 | if (viafb_CRT_ON) { | 625 | if (viafb_CRT_ON) { |
776 | if (viafb_primary_dev == CRT_Device) | 626 | if (viafb_primary_dev == CRT_Device) |
777 | viaparinfo->crt_setting_info->iga_path = IGA1; | 627 | crt_iga_path = IGA1; |
778 | else | 628 | else |
779 | viaparinfo->crt_setting_info->iga_path = IGA2; | 629 | crt_iga_path = IGA2; |
780 | } | 630 | } |
781 | 631 | ||
782 | if (viafb_DVI_ON) { | 632 | if (viafb_DVI_ON) { |
@@ -793,8 +643,7 @@ void viafb_set_iga_path(void) | |||
793 | UNICHROME_CLE266)) { | 643 | UNICHROME_CLE266)) { |
794 | viaparinfo-> | 644 | viaparinfo-> |
795 | lvds_setting_info->iga_path = IGA2; | 645 | lvds_setting_info->iga_path = IGA2; |
796 | viaparinfo-> | 646 | crt_iga_path = IGA1; |
797 | crt_setting_info->iga_path = IGA1; | ||
798 | viaparinfo-> | 647 | viaparinfo-> |
799 | tmds_setting_info->iga_path = IGA1; | 648 | tmds_setting_info->iga_path = IGA1; |
800 | } else | 649 | } else |
@@ -814,10 +663,10 @@ void viafb_set_iga_path(void) | |||
814 | viafb_SAMM_ON = 0; | 663 | viafb_SAMM_ON = 0; |
815 | 664 | ||
816 | if (viafb_CRT_ON && viafb_LCD_ON) { | 665 | if (viafb_CRT_ON && viafb_LCD_ON) { |
817 | viaparinfo->crt_setting_info->iga_path = IGA1; | 666 | crt_iga_path = IGA1; |
818 | viaparinfo->lvds_setting_info->iga_path = IGA2; | 667 | viaparinfo->lvds_setting_info->iga_path = IGA2; |
819 | } else if (viafb_CRT_ON && viafb_DVI_ON) { | 668 | } else if (viafb_CRT_ON && viafb_DVI_ON) { |
820 | viaparinfo->crt_setting_info->iga_path = IGA1; | 669 | crt_iga_path = IGA1; |
821 | viaparinfo->tmds_setting_info->iga_path = IGA2; | 670 | viaparinfo->tmds_setting_info->iga_path = IGA2; |
822 | } else if (viafb_LCD_ON && viafb_DVI_ON) { | 671 | } else if (viafb_LCD_ON && viafb_DVI_ON) { |
823 | viaparinfo->tmds_setting_info->iga_path = IGA1; | 672 | viaparinfo->tmds_setting_info->iga_path = IGA1; |
@@ -826,7 +675,7 @@ void viafb_set_iga_path(void) | |||
826 | viaparinfo->lvds_setting_info->iga_path = IGA2; | 675 | viaparinfo->lvds_setting_info->iga_path = IGA2; |
827 | viaparinfo->lvds_setting_info2->iga_path = IGA2; | 676 | viaparinfo->lvds_setting_info2->iga_path = IGA2; |
828 | } else if (viafb_CRT_ON) { | 677 | } else if (viafb_CRT_ON) { |
829 | viaparinfo->crt_setting_info->iga_path = IGA1; | 678 | crt_iga_path = IGA1; |
830 | } else if (viafb_LCD_ON) { | 679 | } else if (viafb_LCD_ON) { |
831 | viaparinfo->lvds_setting_info->iga_path = IGA2; | 680 | viaparinfo->lvds_setting_info->iga_path = IGA2; |
832 | } else if (viafb_DVI_ON) { | 681 | } else if (viafb_DVI_ON) { |
@@ -837,7 +686,7 @@ void viafb_set_iga_path(void) | |||
837 | viaparinfo->shared->iga1_devices = 0; | 686 | viaparinfo->shared->iga1_devices = 0; |
838 | viaparinfo->shared->iga2_devices = 0; | 687 | viaparinfo->shared->iga2_devices = 0; |
839 | if (viafb_CRT_ON) { | 688 | if (viafb_CRT_ON) { |
840 | if (viaparinfo->crt_setting_info->iga_path == IGA1) | 689 | if (crt_iga_path == IGA1) |
841 | viaparinfo->shared->iga1_devices |= VIA_CRT; | 690 | viaparinfo->shared->iga1_devices |= VIA_CRT; |
842 | else | 691 | else |
843 | viaparinfo->shared->iga2_devices |= VIA_CRT; | 692 | viaparinfo->shared->iga2_devices |= VIA_CRT; |
@@ -875,6 +724,10 @@ void viafb_set_iga_path(void) | |||
875 | viaparinfo->chip_info-> | 724 | viaparinfo->chip_info-> |
876 | lvds_chip_info2.output_interface); | 725 | lvds_chip_info2.output_interface); |
877 | } | 726 | } |
727 | |||
728 | /* looks like the OLPC has its display wired to DVP1 and LVDS2 */ | ||
729 | if (machine_is_olpc()) | ||
730 | viaparinfo->shared->iga2_devices = VIA_DVP1 | VIA_LVDS2; | ||
878 | } | 731 | } |
879 | 732 | ||
880 | static void set_color_register(u8 index, u8 red, u8 green, u8 blue) | 733 | static void set_color_register(u8 index, u8 red, u8 green, u8 blue) |
@@ -1162,25 +1015,17 @@ void via_odev_to_seq(struct seq_file *m, u32 odev) | |||
1162 | 1015 | ||
1163 | static void load_fix_bit_crtc_reg(void) | 1016 | static void load_fix_bit_crtc_reg(void) |
1164 | { | 1017 | { |
1018 | viafb_unlock_crt(); | ||
1019 | |||
1165 | /* always set to 1 */ | 1020 | /* always set to 1 */ |
1166 | viafb_write_reg_mask(CR03, VIACR, 0x80, BIT7); | 1021 | viafb_write_reg_mask(CR03, VIACR, 0x80, BIT7); |
1167 | /* line compare should set all bits = 1 (extend modes) */ | 1022 | /* line compare should set all bits = 1 (extend modes) */ |
1168 | viafb_write_reg(CR18, VIACR, 0xff); | ||
1169 | /* line compare should set all bits = 1 (extend modes) */ | ||
1170 | viafb_write_reg_mask(CR07, VIACR, 0x10, BIT4); | ||
1171 | /* line compare should set all bits = 1 (extend modes) */ | ||
1172 | viafb_write_reg_mask(CR09, VIACR, 0x40, BIT6); | ||
1173 | /* line compare should set all bits = 1 (extend modes) */ | ||
1174 | viafb_write_reg_mask(CR35, VIACR, 0x10, BIT4); | 1023 | viafb_write_reg_mask(CR35, VIACR, 0x10, BIT4); |
1175 | /* line compare should set all bits = 1 (extend modes) */ | 1024 | /* line compare should set all bits = 1 (extend modes) */ |
1176 | viafb_write_reg_mask(CR33, VIACR, 0x06, BIT0 + BIT1 + BIT2); | 1025 | viafb_write_reg_mask(CR33, VIACR, 0x06, BIT0 + BIT1 + BIT2); |
1177 | /*viafb_write_reg_mask(CR32, VIACR, 0x01, BIT0); */ | 1026 | /*viafb_write_reg_mask(CR32, VIACR, 0x01, BIT0); */ |
1178 | /* extend mode always set to e3h */ | 1027 | |
1179 | viafb_write_reg(CR17, VIACR, 0xe3); | 1028 | viafb_lock_crt(); |
1180 | /* extend mode always set to 0h */ | ||
1181 | viafb_write_reg(CR08, VIACR, 0x00); | ||
1182 | /* extend mode always set to 0h */ | ||
1183 | viafb_write_reg(CR14, VIACR, 0x00); | ||
1184 | 1029 | ||
1185 | /* If K8M800, enable Prefetch Mode. */ | 1030 | /* If K8M800, enable Prefetch Mode. */ |
1186 | if ((viaparinfo->chip_info->gfx_chip_name == UNICHROME_K800) | 1031 | if ((viaparinfo->chip_info->gfx_chip_name == UNICHROME_K800) |
@@ -1601,69 +1446,54 @@ void viafb_load_FIFO_reg(int set_iga, int hor_active, int ver_active) | |||
1601 | 1446 | ||
1602 | } | 1447 | } |
1603 | 1448 | ||
1604 | static u32 cle266_encode_pll(struct pll_config pll) | 1449 | static struct via_pll_config get_pll_config(struct pll_limit *limits, int size, |
1605 | { | ||
1606 | return (pll.multiplier << 8) | ||
1607 | | (pll.rshift << 6) | ||
1608 | | pll.divisor; | ||
1609 | } | ||
1610 | |||
1611 | static u32 k800_encode_pll(struct pll_config pll) | ||
1612 | { | ||
1613 | return ((pll.divisor - 2) << 16) | ||
1614 | | (pll.rshift << 10) | ||
1615 | | (pll.multiplier - 2); | ||
1616 | } | ||
1617 | |||
1618 | static u32 vx855_encode_pll(struct pll_config pll) | ||
1619 | { | ||
1620 | return (pll.divisor << 16) | ||
1621 | | (pll.rshift << 10) | ||
1622 | | pll.multiplier; | ||
1623 | } | ||
1624 | |||
1625 | static inline u32 get_pll_internal_frequency(u32 ref_freq, | ||
1626 | struct pll_config pll) | ||
1627 | { | ||
1628 | return ref_freq / pll.divisor * pll.multiplier; | ||
1629 | } | ||
1630 | |||
1631 | static inline u32 get_pll_output_frequency(u32 ref_freq, struct pll_config pll) | ||
1632 | { | ||
1633 | return get_pll_internal_frequency(ref_freq, pll)>>pll.rshift; | ||
1634 | } | ||
1635 | |||
1636 | static struct pll_config get_pll_config(struct pll_config *config, int size, | ||
1637 | int clk) | 1450 | int clk) |
1638 | { | 1451 | { |
1639 | struct pll_config best = config[0]; | 1452 | struct via_pll_config cur, up, down, best = {0, 1, 0}; |
1640 | const u32 f0 = 14318180; /* X1 frequency */ | 1453 | const u32 f0 = 14318180; /* X1 frequency */ |
1641 | int i; | 1454 | int i, f; |
1642 | 1455 | ||
1643 | for (i = 1; i < size; i++) { | 1456 | for (i = 0; i < size; i++) { |
1644 | if (abs(get_pll_output_frequency(f0, config[i]) - clk) | 1457 | cur.rshift = limits[i].rshift; |
1645 | < abs(get_pll_output_frequency(f0, best) - clk)) | 1458 | cur.divisor = limits[i].divisor; |
1646 | best = config[i]; | 1459 | cur.multiplier = clk / ((f0 / cur.divisor)>>cur.rshift); |
1460 | f = abs(get_pll_output_frequency(f0, cur) - clk); | ||
1461 | up = down = cur; | ||
1462 | up.multiplier++; | ||
1463 | down.multiplier--; | ||
1464 | if (abs(get_pll_output_frequency(f0, up) - clk) < f) | ||
1465 | cur = up; | ||
1466 | else if (abs(get_pll_output_frequency(f0, down) - clk) < f) | ||
1467 | cur = down; | ||
1468 | |||
1469 | if (cur.multiplier < limits[i].multiplier_min) | ||
1470 | cur.multiplier = limits[i].multiplier_min; | ||
1471 | else if (cur.multiplier > limits[i].multiplier_max) | ||
1472 | cur.multiplier = limits[i].multiplier_max; | ||
1473 | |||
1474 | f = abs(get_pll_output_frequency(f0, cur) - clk); | ||
1475 | if (f < abs(get_pll_output_frequency(f0, best) - clk)) | ||
1476 | best = cur; | ||
1647 | } | 1477 | } |
1648 | 1478 | ||
1649 | return best; | 1479 | return best; |
1650 | } | 1480 | } |
1651 | 1481 | ||
1652 | u32 viafb_get_clk_value(int clk) | 1482 | static struct via_pll_config get_best_pll_config(int clk) |
1653 | { | 1483 | { |
1654 | u32 value = 0; | 1484 | struct via_pll_config config; |
1655 | 1485 | ||
1656 | switch (viaparinfo->chip_info->gfx_chip_name) { | 1486 | switch (viaparinfo->chip_info->gfx_chip_name) { |
1657 | case UNICHROME_CLE266: | 1487 | case UNICHROME_CLE266: |
1658 | case UNICHROME_K400: | 1488 | case UNICHROME_K400: |
1659 | value = cle266_encode_pll(get_pll_config(cle266_pll_config, | 1489 | config = get_pll_config(cle266_pll_limits, |
1660 | ARRAY_SIZE(cle266_pll_config), clk)); | 1490 | ARRAY_SIZE(cle266_pll_limits), clk); |
1661 | break; | 1491 | break; |
1662 | case UNICHROME_K800: | 1492 | case UNICHROME_K800: |
1663 | case UNICHROME_PM800: | 1493 | case UNICHROME_PM800: |
1664 | case UNICHROME_CN700: | 1494 | case UNICHROME_CN700: |
1665 | value = k800_encode_pll(get_pll_config(k800_pll_config, | 1495 | config = get_pll_config(k800_pll_limits, |
1666 | ARRAY_SIZE(k800_pll_config), clk)); | 1496 | ARRAY_SIZE(k800_pll_limits), clk); |
1667 | break; | 1497 | break; |
1668 | case UNICHROME_CX700: | 1498 | case UNICHROME_CX700: |
1669 | case UNICHROME_CN750: | 1499 | case UNICHROME_CN750: |
@@ -1671,92 +1501,28 @@ u32 viafb_get_clk_value(int clk) | |||
1671 | case UNICHROME_P4M890: | 1501 | case UNICHROME_P4M890: |
1672 | case UNICHROME_P4M900: | 1502 | case UNICHROME_P4M900: |
1673 | case UNICHROME_VX800: | 1503 | case UNICHROME_VX800: |
1674 | value = k800_encode_pll(get_pll_config(cx700_pll_config, | 1504 | config = get_pll_config(cx700_pll_limits, |
1675 | ARRAY_SIZE(cx700_pll_config), clk)); | 1505 | ARRAY_SIZE(cx700_pll_limits), clk); |
1676 | break; | 1506 | break; |
1677 | case UNICHROME_VX855: | 1507 | case UNICHROME_VX855: |
1678 | case UNICHROME_VX900: | 1508 | case UNICHROME_VX900: |
1679 | value = vx855_encode_pll(get_pll_config(vx855_pll_config, | 1509 | config = get_pll_config(vx855_pll_limits, |
1680 | ARRAY_SIZE(vx855_pll_config), clk)); | 1510 | ARRAY_SIZE(vx855_pll_limits), clk); |
1681 | break; | 1511 | break; |
1682 | } | 1512 | } |
1683 | 1513 | ||
1684 | return value; | 1514 | return config; |
1685 | } | 1515 | } |
1686 | 1516 | ||
1687 | /* Set VCLK*/ | 1517 | /* Set VCLK*/ |
1688 | void viafb_set_vclock(u32 clk, int set_iga) | 1518 | void viafb_set_vclock(u32 clk, int set_iga) |
1689 | { | 1519 | { |
1690 | /* H.W. Reset : ON */ | 1520 | struct via_pll_config config = get_best_pll_config(clk); |
1691 | viafb_write_reg_mask(CR17, VIACR, 0x00, BIT7); | ||
1692 | 1521 | ||
1693 | if (set_iga == IGA1) { | 1522 | if (set_iga == IGA1) |
1694 | /* Change D,N FOR VCLK */ | 1523 | clock.set_primary_pll(config); |
1695 | switch (viaparinfo->chip_info->gfx_chip_name) { | 1524 | if (set_iga == IGA2) |
1696 | case UNICHROME_CLE266: | 1525 | clock.set_secondary_pll(config); |
1697 | case UNICHROME_K400: | ||
1698 | via_write_reg(VIASR, SR46, (clk & 0x00FF)); | ||
1699 | via_write_reg(VIASR, SR47, (clk & 0xFF00) >> 8); | ||
1700 | break; | ||
1701 | |||
1702 | case UNICHROME_K800: | ||
1703 | case UNICHROME_PM800: | ||
1704 | case UNICHROME_CN700: | ||
1705 | case UNICHROME_CX700: | ||
1706 | case UNICHROME_CN750: | ||
1707 | case UNICHROME_K8M890: | ||
1708 | case UNICHROME_P4M890: | ||
1709 | case UNICHROME_P4M900: | ||
1710 | case UNICHROME_VX800: | ||
1711 | case UNICHROME_VX855: | ||
1712 | case UNICHROME_VX900: | ||
1713 | via_write_reg(VIASR, SR44, (clk & 0x0000FF)); | ||
1714 | via_write_reg(VIASR, SR45, (clk & 0x00FF00) >> 8); | ||
1715 | via_write_reg(VIASR, SR46, (clk & 0xFF0000) >> 16); | ||
1716 | break; | ||
1717 | } | ||
1718 | } | ||
1719 | |||
1720 | if (set_iga == IGA2) { | ||
1721 | /* Change D,N FOR LCK */ | ||
1722 | switch (viaparinfo->chip_info->gfx_chip_name) { | ||
1723 | case UNICHROME_CLE266: | ||
1724 | case UNICHROME_K400: | ||
1725 | via_write_reg(VIASR, SR44, (clk & 0x00FF)); | ||
1726 | via_write_reg(VIASR, SR45, (clk & 0xFF00) >> 8); | ||
1727 | break; | ||
1728 | |||
1729 | case UNICHROME_K800: | ||
1730 | case UNICHROME_PM800: | ||
1731 | case UNICHROME_CN700: | ||
1732 | case UNICHROME_CX700: | ||
1733 | case UNICHROME_CN750: | ||
1734 | case UNICHROME_K8M890: | ||
1735 | case UNICHROME_P4M890: | ||
1736 | case UNICHROME_P4M900: | ||
1737 | case UNICHROME_VX800: | ||
1738 | case UNICHROME_VX855: | ||
1739 | case UNICHROME_VX900: | ||
1740 | via_write_reg(VIASR, SR4A, (clk & 0x0000FF)); | ||
1741 | via_write_reg(VIASR, SR4B, (clk & 0x00FF00) >> 8); | ||
1742 | via_write_reg(VIASR, SR4C, (clk & 0xFF0000) >> 16); | ||
1743 | break; | ||
1744 | } | ||
1745 | } | ||
1746 | |||
1747 | /* H.W. Reset : OFF */ | ||
1748 | viafb_write_reg_mask(CR17, VIACR, 0x80, BIT7); | ||
1749 | |||
1750 | /* Reset PLL */ | ||
1751 | if (set_iga == IGA1) { | ||
1752 | viafb_write_reg_mask(SR40, VIASR, 0x02, BIT1); | ||
1753 | viafb_write_reg_mask(SR40, VIASR, 0x00, BIT1); | ||
1754 | } | ||
1755 | |||
1756 | if (set_iga == IGA2) { | ||
1757 | viafb_write_reg_mask(SR40, VIASR, 0x04, BIT2); | ||
1758 | viafb_write_reg_mask(SR40, VIASR, 0x00, BIT2); | ||
1759 | } | ||
1760 | 1526 | ||
1761 | /* Fire! */ | 1527 | /* Fire! */ |
1762 | via_write_misc_reg_mask(0x0C, 0x0C); /* select external clock */ | 1528 | via_write_misc_reg_mask(0x0C, 0x0C); /* select external clock */ |
@@ -2002,7 +1768,7 @@ void viafb_fill_crtc_timing(struct crt_mode_table *crt_table, | |||
2002 | int i; | 1768 | int i; |
2003 | int index = 0; | 1769 | int index = 0; |
2004 | int h_addr, v_addr; | 1770 | int h_addr, v_addr; |
2005 | u32 pll_D_N, clock, refresh = viafb_refresh; | 1771 | u32 clock, refresh = viafb_refresh; |
2006 | 1772 | ||
2007 | if (viafb_SAMM_ON && set_iga == IGA2) | 1773 | if (viafb_SAMM_ON && set_iga == IGA2) |
2008 | refresh = viafb_refresh1; | 1774 | refresh = viafb_refresh1; |
@@ -2033,8 +1799,6 @@ void viafb_fill_crtc_timing(struct crt_mode_table *crt_table, | |||
2033 | v_addr = crt_reg.ver_addr; | 1799 | v_addr = crt_reg.ver_addr; |
2034 | if (set_iga == IGA1) { | 1800 | if (set_iga == IGA1) { |
2035 | viafb_unlock_crt(); | 1801 | viafb_unlock_crt(); |
2036 | viafb_write_reg(CR09, VIACR, 0x00); /*initial CR09=0 */ | ||
2037 | viafb_write_reg_mask(CR11, VIACR, 0x00, BIT4 + BIT5 + BIT6); | ||
2038 | viafb_write_reg_mask(CR17, VIACR, 0x00, BIT7); | 1802 | viafb_write_reg_mask(CR17, VIACR, 0x00, BIT7); |
2039 | } | 1803 | } |
2040 | 1804 | ||
@@ -2047,7 +1811,6 @@ void viafb_fill_crtc_timing(struct crt_mode_table *crt_table, | |||
2047 | break; | 1811 | break; |
2048 | } | 1812 | } |
2049 | 1813 | ||
2050 | load_fix_bit_crtc_reg(); | ||
2051 | viafb_lock_crt(); | 1814 | viafb_lock_crt(); |
2052 | viafb_write_reg_mask(CR17, VIACR, 0x80, BIT7); | 1815 | viafb_write_reg_mask(CR17, VIACR, 0x80, BIT7); |
2053 | viafb_load_fetch_count_reg(h_addr, bpp_byte, set_iga); | 1816 | viafb_load_fetch_count_reg(h_addr, bpp_byte, set_iga); |
@@ -2059,20 +1822,17 @@ void viafb_fill_crtc_timing(struct crt_mode_table *crt_table, | |||
2059 | 1822 | ||
2060 | clock = crt_reg.hor_total * crt_reg.ver_total | 1823 | clock = crt_reg.hor_total * crt_reg.ver_total |
2061 | * crt_table[index].refresh_rate; | 1824 | * crt_table[index].refresh_rate; |
2062 | pll_D_N = viafb_get_clk_value(clock); | 1825 | viafb_set_vclock(clock, set_iga); |
2063 | DEBUG_MSG(KERN_INFO "PLL=%x", pll_D_N); | ||
2064 | viafb_set_vclock(pll_D_N, set_iga); | ||
2065 | 1826 | ||
2066 | } | 1827 | } |
2067 | 1828 | ||
2068 | void __devinit viafb_init_chip_info(int chip_type) | 1829 | void __devinit viafb_init_chip_info(int chip_type) |
2069 | { | 1830 | { |
1831 | via_clock_init(&clock, chip_type); | ||
2070 | init_gfx_chip_info(chip_type); | 1832 | init_gfx_chip_info(chip_type); |
2071 | init_tmds_chip_info(); | 1833 | init_tmds_chip_info(); |
2072 | init_lvds_chip_info(); | 1834 | init_lvds_chip_info(); |
2073 | 1835 | ||
2074 | viaparinfo->crt_setting_info->iga_path = IGA1; | ||
2075 | |||
2076 | /*Set IGA path for each device */ | 1836 | /*Set IGA path for each device */ |
2077 | viafb_set_iga_path(); | 1837 | viafb_set_iga_path(); |
2078 | 1838 | ||
@@ -2354,6 +2114,7 @@ int viafb_setmode(struct VideoModeTable *vmode_tbl, int video_bpp, | |||
2354 | outb(0x00, VIAAR); | 2114 | outb(0x00, VIAAR); |
2355 | 2115 | ||
2356 | /* Write Common Setting for Video Mode */ | 2116 | /* Write Common Setting for Video Mode */ |
2117 | viafb_write_regx(common_vga, ARRAY_SIZE(common_vga)); | ||
2357 | switch (viaparinfo->chip_info->gfx_chip_name) { | 2118 | switch (viaparinfo->chip_info->gfx_chip_name) { |
2358 | case UNICHROME_CLE266: | 2119 | case UNICHROME_CLE266: |
2359 | viafb_write_regx(CLE266_ModeXregs, NUM_TOTAL_CLE266_ModeXregs); | 2120 | viafb_write_regx(CLE266_ModeXregs, NUM_TOTAL_CLE266_ModeXregs); |
@@ -2400,9 +2161,6 @@ int viafb_setmode(struct VideoModeTable *vmode_tbl, int video_bpp, | |||
2400 | 2161 | ||
2401 | viafb_write_reg_mask(0x15, VIASR, 0xA2, 0xA2); | 2162 | viafb_write_reg_mask(0x15, VIASR, 0xA2, 0xA2); |
2402 | 2163 | ||
2403 | /* Write CRTC */ | ||
2404 | viafb_fill_crtc_timing(crt_timing, vmode_tbl, video_bpp / 8, IGA1); | ||
2405 | |||
2406 | /* Write Graphic Controller */ | 2164 | /* Write Graphic Controller */ |
2407 | for (i = 0; i < StdGR; i++) | 2165 | for (i = 0; i < StdGR; i++) |
2408 | via_write_reg(VIAGR, i, VPIT.GR[i]); | 2166 | via_write_reg(VIAGR, i, VPIT.GR[i]); |
@@ -2432,6 +2190,7 @@ int viafb_setmode(struct VideoModeTable *vmode_tbl, int video_bpp, | |||
2432 | } | 2190 | } |
2433 | } | 2191 | } |
2434 | 2192 | ||
2193 | load_fix_bit_crtc_reg(); | ||
2435 | via_set_primary_pitch(viafbinfo->fix.line_length); | 2194 | via_set_primary_pitch(viafbinfo->fix.line_length); |
2436 | via_set_secondary_pitch(viafb_dual_fb ? viafbinfo1->fix.line_length | 2195 | via_set_secondary_pitch(viafb_dual_fb ? viafbinfo1->fix.line_length |
2437 | : viafbinfo->fix.line_length); | 2196 | : viafbinfo->fix.line_length); |
@@ -2451,15 +2210,15 @@ int viafb_setmode(struct VideoModeTable *vmode_tbl, int video_bpp, | |||
2451 | 2210 | ||
2452 | /* CRT set mode */ | 2211 | /* CRT set mode */ |
2453 | if (viafb_CRT_ON) { | 2212 | if (viafb_CRT_ON) { |
2454 | if (viafb_SAMM_ON && (viaparinfo->crt_setting_info->iga_path == | 2213 | if (viafb_SAMM_ON && |
2455 | IGA2)) { | 2214 | viaparinfo->shared->iga2_devices & VIA_CRT) { |
2456 | viafb_fill_crtc_timing(crt_timing1, vmode_tbl1, | 2215 | viafb_fill_crtc_timing(crt_timing1, vmode_tbl1, |
2457 | video_bpp1 / 8, | 2216 | video_bpp1 / 8, IGA2); |
2458 | viaparinfo->crt_setting_info->iga_path); | ||
2459 | } else { | 2217 | } else { |
2460 | viafb_fill_crtc_timing(crt_timing, vmode_tbl, | 2218 | viafb_fill_crtc_timing(crt_timing, vmode_tbl, |
2461 | video_bpp / 8, | 2219 | video_bpp / 8, |
2462 | viaparinfo->crt_setting_info->iga_path); | 2220 | (viaparinfo->shared->iga1_devices & VIA_CRT) |
2221 | ? IGA1 : IGA2); | ||
2463 | } | 2222 | } |
2464 | 2223 | ||
2465 | /* Patch if set_hres is not 8 alignment (1366) to viafb_setmode | 2224 | /* Patch if set_hres is not 8 alignment (1366) to viafb_setmode |
@@ -2557,6 +2316,33 @@ int viafb_setmode(struct VideoModeTable *vmode_tbl, int video_bpp, | |||
2557 | get_sync(viafbinfo1)); | 2316 | get_sync(viafbinfo1)); |
2558 | } | 2317 | } |
2559 | 2318 | ||
2319 | clock.set_engine_pll_state(VIA_STATE_ON); | ||
2320 | clock.set_primary_clock_source(VIA_CLKSRC_X1, true); | ||
2321 | clock.set_secondary_clock_source(VIA_CLKSRC_X1, true); | ||
2322 | |||
2323 | #ifdef CONFIG_FB_VIA_X_COMPATIBILITY | ||
2324 | clock.set_primary_pll_state(VIA_STATE_ON); | ||
2325 | clock.set_primary_clock_state(VIA_STATE_ON); | ||
2326 | clock.set_secondary_pll_state(VIA_STATE_ON); | ||
2327 | clock.set_secondary_clock_state(VIA_STATE_ON); | ||
2328 | #else | ||
2329 | if (viaparinfo->shared->iga1_devices) { | ||
2330 | clock.set_primary_pll_state(VIA_STATE_ON); | ||
2331 | clock.set_primary_clock_state(VIA_STATE_ON); | ||
2332 | } else { | ||
2333 | clock.set_primary_pll_state(VIA_STATE_OFF); | ||
2334 | clock.set_primary_clock_state(VIA_STATE_OFF); | ||
2335 | } | ||
2336 | |||
2337 | if (viaparinfo->shared->iga2_devices) { | ||
2338 | clock.set_secondary_pll_state(VIA_STATE_ON); | ||
2339 | clock.set_secondary_clock_state(VIA_STATE_ON); | ||
2340 | } else { | ||
2341 | clock.set_secondary_pll_state(VIA_STATE_OFF); | ||
2342 | clock.set_secondary_clock_state(VIA_STATE_OFF); | ||
2343 | } | ||
2344 | #endif /*CONFIG_FB_VIA_X_COMPATIBILITY*/ | ||
2345 | |||
2560 | via_set_state(devices, VIA_STATE_ON); | 2346 | via_set_state(devices, VIA_STATE_ON); |
2561 | device_screen_on(); | 2347 | device_screen_on(); |
2562 | return 1; | 2348 | return 1; |
@@ -2598,8 +2384,12 @@ int viafb_get_refresh(int hres, int vres, u32 long_refresh) | |||
2598 | best = &vmode->crtc[i]; | 2384 | best = &vmode->crtc[i]; |
2599 | } | 2385 | } |
2600 | 2386 | ||
2601 | if (abs(best->refresh_rate - long_refresh) > 3) | 2387 | if (abs(best->refresh_rate - long_refresh) > 3) { |
2602 | return 60; | 2388 | if (hres == 1200 && vres == 900) |
2389 | return 49; /* OLPC DCON only supports 50 Hz */ | ||
2390 | else | ||
2391 | return 60; | ||
2392 | } | ||
2603 | 2393 | ||
2604 | return best->refresh_rate; | 2394 | return best->refresh_rate; |
2605 | } | 2395 | } |