1/* Copyright (c) 2005 Advanced Micro Devices, Inc.
2 *
3 * Permission is hereby granted, free of charge, to any person obtaining a copy
4 * of this software and associated documentation files (the "Software"), to
5 * deal in the Software without restriction, including without limitation the
6 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
7 * sell copies of the Software, and to permit persons to whom the Software is
8 * furnished to do so, subject to the following conditions:
9 *
10 * The above copyright notice and this permission notice shall be included in
11 * all copies or substantial portions of the Software.
12 *
13 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
18 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
19 * IN THE SOFTWARE.
20 *
21 * Neither the name of the Advanced Micro Devices, Inc. nor the names of its
22 * contributors may be used to endorse or promote products derived from this
23 * software without specific prior written permission.
24 * */
25
26/*
27 * This file contains routines to control the SC1200 video input port (VIP)
28 * hardware.
29 * */
30
31/*----------------------------------------------------------------------------
32 * gfx_set_vip_enable
33 *
34 * This routine enables or disables the writes to memory from the video port.
35 *----------------------------------------------------------------------------
36 */
37#if GFX_VIP_DYNAMIC
38int
39sc1200_set_vip_enable(int enable)
40#else
41int
42gfx_set_vip_enable(int enable)
43#endif
44{
45    unsigned long value;
46
47    value = READ_VIP32(SC1200_VIP_CONTROL);
48    if (enable)
49        value |= SC1200_VIP_DATA_CAPTURE_EN;
50    else
51        value &= ~SC1200_VIP_DATA_CAPTURE_EN;
52    WRITE_VIP32(SC1200_VIP_CONTROL, value);
53    return (0);
54}
55
56/*----------------------------------------------------------------------------
57 * gfx_set_vip_capture_run_mode
58 *
59 * This routine selects VIP capture run mode.
60 *----------------------------------------------------------------------------
61 */
62#if GFX_VIP_DYNAMIC
63int
64sc1200_set_vip_capture_run_mode(int mode)
65#else
66int
67gfx_set_vip_capture_run_mode(int mode)
68#endif
69{
70    unsigned long value;
71
72    value = READ_VIP32(SC1200_VIP_CONTROL);
73    value &= ~SC1200_CAPTURE_RUN_MODE_MASK;
74    switch (mode) {
75    case VIP_CAPTURE_STOP_LINE:
76        value |= SC1200_CAPTURE_RUN_MODE_STOP_LINE;
77        break;
78    case VIP_CAPTURE_STOP_FIELD:
79        value |= SC1200_CAPTURE_RUN_MODE_STOP_FIELD;
80        break;
81    case VIP_CAPTURE_START_FIELD:
82        value |= SC1200_CAPTURE_RUN_MODE_START;
83        break;
84    default:
85        return GFX_STATUS_BAD_PARAMETER;
86    }
87    WRITE_VIP32(SC1200_VIP_CONTROL, value);
88    return (0);
89}
90
91/*----------------------------------------------------------------------------
92 * gfx_set_vip_base
93 *
94 * This routine sets the odd and even base address values for the VIP memory
95 * buffer.
96 *----------------------------------------------------------------------------
97 */
98#if GFX_VIP_DYNAMIC
99int
100sc1200_set_vip_base(unsigned long even, unsigned long odd)
101#else
102int
103gfx_set_vip_base(unsigned long even, unsigned long odd)
104#endif
105{
106    /* TRUE OFFSET IS SPECIFIED, NEED TO SET BIT 23 FOR HARDWARE */
107
108    if (even)
109        WRITE_VIP32(SC1200_VIP_EVEN_BASE,
110                    even + (unsigned long) gfx_phys_fbptr);
111    if (odd)
112        WRITE_VIP32(SC1200_VIP_ODD_BASE, odd + (unsigned long) gfx_phys_fbptr);
113    return (0);
114}
115
116/*----------------------------------------------------------------------------
117 * gfx_set_vip_pitch
118 *
119 * This routine sets the number of bytes between scanlines for the VIP data.
120 *----------------------------------------------------------------------------
121 */
122#if GFX_VIP_DYNAMIC
123int
124sc1200_set_vip_pitch(unsigned long pitch)
125#else
126int
127gfx_set_vip_pitch(unsigned long pitch)
128#endif
129{
130    WRITE_VIP32(SC1200_VIP_PITCH, pitch & SC1200_VIP_PITCH_MASK);
131    return (0);
132}
133
134/*----------------------------------------------------------------------------
135 * gfx_set_vip_mode
136 *
137 * This routine sets the VIP operating mode.
138 *----------------------------------------------------------------------------
139 */
140#if GFX_VIP_DYNAMIC
141int
142sc1200_set_vip_mode(int mode)
143#else
144int
145gfx_set_vip_mode(int mode)
146#endif
147{
148    unsigned long config;
149
150    config = READ_VIP32(SC1200_VIP_CONFIG);
151    config &= ~SC1200_VIP_MODE_MASK;
152    switch (mode) {
153    case VIP_MODE_C:
154        WRITE_VIP32(SC1200_VIP_CONFIG, config | SC1200_VIP_MODE_C);
155        break;
156    default:
157        return GFX_STATUS_BAD_PARAMETER;
158    }
159    return (0);
160}
161
162/*----------------------------------------------------------------------------
163 * gfx_set_vbi_enable
164 *
165 * This routine enables or disables the VBI data capture.
166 *----------------------------------------------------------------------------
167 */
168#if GFX_VIP_DYNAMIC
169int
170sc1200_set_vbi_enable(int enable)
171#else
172int
173gfx_set_vbi_enable(int enable)
174#endif
175{
176    unsigned long value;
177
178    value = READ_VIP32(SC1200_VIP_CONTROL);
179    if (enable)
180        value |= SC1200_VIP_VBI_CAPTURE_EN;
181    else
182        value &= ~SC1200_VIP_VBI_CAPTURE_EN;
183    WRITE_VIP32(SC1200_VIP_CONTROL, value);
184    return (0);
185}
186
187/*----------------------------------------------------------------------------
188 * gfx_set_vbi_mode
189 *
190 * This routine sets the VBI data types captured to memory.
191 * It receives a mask of all enabled types.
192 *----------------------------------------------------------------------------
193 */
194#if GFX_VIP_DYNAMIC
195int
196sc1200_set_vbi_mode(int mode)
197#else
198int
199gfx_set_vbi_mode(int mode)
200#endif
201{
202    unsigned long config;
203
204    config = READ_VIP32(SC1200_VIP_CONFIG);
205    config &=
206        ~(SC1200_VBI_ANCILLARY_TO_MEMORY | SC1200_VBI_TASK_A_TO_MEMORY |
207          SC1200_VBI_TASK_B_TO_MEMORY);
208
209    if (mode & VBI_ANCILLARY)
210        config |= SC1200_VBI_ANCILLARY_TO_MEMORY;
211    if (mode & VBI_TASK_A)
212        config |= SC1200_VBI_TASK_A_TO_MEMORY;
213    if (mode & VBI_TASK_B)
214        config |= SC1200_VBI_TASK_B_TO_MEMORY;
215    WRITE_VIP32(SC1200_VIP_CONFIG, config);
216    return (0);
217}
218
219/*----------------------------------------------------------------------------
220 * gfx_set_vbi_base
221 *
222 * This routine sets the odd and even base address values for VBI capture.
223 *
224 * "even" and "odd" should contain 16-byte aligned physical addresses.
225 *----------------------------------------------------------------------------
226 */
227#if GFX_VIP_DYNAMIC
228int
229sc1200_set_vbi_base(unsigned long even, unsigned long odd)
230#else
231int
232gfx_set_vbi_base(unsigned long even, unsigned long odd)
233#endif
234{
235    /* VIP HW REQUIRES THAT BASE ADDRESSES BE 16-BYTE ALIGNED */
236
237    if (even)
238        WRITE_VIP32(SC1200_VBI_EVEN_BASE, even & ~0xf);
239    if (odd)
240        WRITE_VIP32(SC1200_VBI_ODD_BASE, odd & ~0xf);
241
242    return (0);
243}
244
245/*----------------------------------------------------------------------------
246 * gfx_set_vbi_pitch
247 *
248 * This routine sets the number of bytes between scanlines for VBI capture.
249 *----------------------------------------------------------------------------
250 */
251#if GFX_VIP_DYNAMIC
252int
253sc1200_set_vbi_pitch(unsigned long pitch)
254#else
255int
256gfx_set_vbi_pitch(unsigned long pitch)
257#endif
258{
259    WRITE_VIP32(SC1200_VBI_PITCH, pitch & SC1200_VBI_PITCH_MASK);
260    return (0);
261}
262
263/*----------------------------------------------------------------------------
264 * gfx_set_vbi_direct
265 *
266 * This routine sets the VBI lines to be passed to the Direct VIP.
267 *----------------------------------------------------------------------------
268 */
269#if GFX_VIP_DYNAMIC
270int
271sc1200_set_vbi_direct(unsigned long even_lines, unsigned long odd_lines)
272#else
273int
274gfx_set_vbi_direct(unsigned long even_lines, unsigned long odd_lines)
275#endif
276{
277    WRITE_VIP32(SC1200_EVEN_DIRECT_VBI_LINE_ENABLE,
278                even_lines & SC1200_DIRECT_VBI_LINE_ENABLE_MASK);
279    WRITE_VIP32(SC1200_ODD_DIRECT_VBI_LINE_ENABLE,
280                odd_lines & SC1200_DIRECT_VBI_LINE_ENABLE_MASK);
281    return (0);
282}
283
284/*----------------------------------------------------------------------------
285 * gfx_set_vbi_interrupt
286 *
287 * This routine enables or disables the VBI field interrupt.
288 *----------------------------------------------------------------------------
289 */
290#if GFX_VIP_DYNAMIC
291int
292sc1200_set_vbi_interrupt(int enable)
293#else
294int
295gfx_set_vbi_interrupt(int enable)
296#endif
297{
298    unsigned long value;
299
300    value = READ_VIP32(SC1200_VIP_CONTROL);
301    if (enable)
302        value |= SC1200_VIP_VBI_FIELD_INTERRUPT_EN;
303    else
304        value &= ~SC1200_VIP_VBI_FIELD_INTERRUPT_EN;
305    WRITE_VIP32(SC1200_VIP_CONTROL, value);
306    return (0);
307}
308
309/*----------------------------------------------------------------------------
310 * gfx_set_vip_bus_request_threshold_high
311 *
312 * This routine sets the VIP FIFO bus request threshold.
313 * If enable is TRUE, VIP FIFO will be set to issue a bus request when it
314 * filled with 64 bytes. If enable is FALSE, VIP FIFO will be set to issue a
315 * bus request when it filled with 32 bytes.
316 *----------------------------------------------------------------------------
317 */
318#if GFX_VIP_DYNAMIC
319int
320sc1200_set_vip_bus_request_threshold_high(int enable)
321#else
322int
323gfx_set_vip_bus_request_threshold_high(int enable)
324#endif
325{
326    unsigned long value;
327
328    value = READ_VIP32(SC1200_VIP_CONFIG);
329    if (enable)
330        value &= ~SC1200_VIP_BUS_REQUEST_THRESHOLD;
331    else
332        value |= SC1200_VIP_BUS_REQUEST_THRESHOLD;
333    WRITE_VIP32(SC1200_VIP_CONFIG, value);
334    return (0);
335}
336
337/*----------------------------------------------------------------------------
338 * gfx_set_vip_last_line
339 *
340 * This routine sets the maximum number of lines captured in each field.
341 *----------------------------------------------------------------------------
342 */
343#if GFX_VIP_DYNAMIC
344int
345sc1200_set_vip_last_line(int last_line)
346#else
347int
348gfx_set_vip_last_line(int last_line)
349#endif
350{
351    unsigned long value;
352
353    /* This feature is implemented in Rev C1 */
354    if (gfx_chip_revision < SC1200_REV_C1)
355        return (GFX_STATUS_OK);
356
357    value = READ_VIP32(SC1200_VIP_LINE_TARGET);
358    value &= ~SC1200_VIP_LAST_LINE_MASK;
359    value |= ((last_line & 0x3FF) << 16);
360    WRITE_VIP32(SC1200_VIP_LINE_TARGET, value);
361    return (GFX_STATUS_OK);
362}
363
364/*----------------------------------------------------------------------------
365 * gfx_test_vip_odd_field
366 *
367 * This routine returns 1 if the current VIP field is odd. Otherwise returns 0
368 *----------------------------------------------------------------------------
369 */
370#if GFX_VIP_DYNAMIC
371int
372sc1200_test_vip_odd_field(void)
373#else
374int
375gfx_test_vip_odd_field(void)
376#endif
377{
378    if (READ_VIP32(SC1200_VIP_STATUS) & SC1200_VIP_CURRENT_FIELD_ODD)
379        return (1);
380    else
381        return (0);
382}
383
384/*----------------------------------------------------------------------------
385 * gfx_test_vip_bases_updated
386 *
387 * This routine returns 1 if all of the VIP base registers have been updated,
388 * i.e. there is no base register which has been written with a new address,
389 * that VIP has not already captured or started capturing into the new address
390 *----------------------------------------------------------------------------
391 */
392#if GFX_VIP_DYNAMIC
393int
394sc1200_test_vip_bases_updated(void)
395#else
396int
397gfx_test_vip_bases_updated(void)
398#endif
399{
400    if (READ_VIP32(SC1200_VIP_STATUS) & SC1200_VIP_BASE_NOT_UPDATED)
401        return (0);
402    else
403        return (1);
404}
405
406/*----------------------------------------------------------------------------
407 * gfx_test_vip_fifo_overflow
408 *
409 * This routine returns 1 if an overflow occurred on the FIFO between the VIP
410 * and the fast X-bus, 0 otherwise.
411 * If an overflow occurred, the overflow status indication is reset.
412 *----------------------------------------------------------------------------
413 */
414#if GFX_VIP_DYNAMIC
415int
416sc1200_test_vip_fifo_overflow(void)
417#else
418int
419gfx_test_vip_fifo_overflow(void)
420#endif
421{
422    if (READ_VIP32(SC1200_VIP_STATUS) & SC1200_VIP_FIFO_OVERFLOW) {
423        /* Bits in vip status register are either read only or reset by
424         * writing 1 */
425        WRITE_VIP32(SC1200_VIP_STATUS, SC1200_VIP_FIFO_OVERFLOW);
426        return (1);
427    }
428    else {
429        return (0);
430    }
431}
432
433/*----------------------------------------------------------------------------
434 * gfx_get_vip_line
435 *
436 * This routine returns the number of the current video line being
437 * received by the VIP interface.
438 *----------------------------------------------------------------------------
439 */
440#if GFX_VIP_DYNAMIC
441int
442sc1200_get_vip_line(void)
443#else
444int
445gfx_get_vip_line(void)
446#endif
447{
448    return (int) (READ_VIP32(SC1200_VIP_CURRENT_LINE) &
449                  SC1200_VIP_CURRENT_LINE_MASK);
450}
451
452/*----------------------------------------------------------------------------
453 * gfx_get_vip_base
454 *----------------------------------------------------------------------------
455 */
456#if GFX_VIP_DYNAMIC
457unsigned long
458sc1200_get_vip_base(int odd)
459#else
460unsigned long
461gfx_get_vip_base(int odd)
462#endif
463{
464    /* MASK BIT 23 AND ABOVE TO MAKE IT A TRUE OFFSET */
465
466    if (odd)
467        return (READ_VIP32(SC1200_VIP_ODD_BASE));
468    return (READ_VIP32(SC1200_VIP_EVEN_BASE));
469}
470
471/*----------------------------------------------------------------------------
472 * gfx_get_vbi_pitch
473 *----------------------------------------------------------------------------
474 */
475#if GFX_VIP_DYNAMIC
476unsigned long
477sc1200_get_vbi_pitch(void)
478#else
479unsigned long
480gfx_get_vbi_pitch(void)
481#endif
482{
483    return (READ_VIP32(SC1200_VBI_PITCH) & SC1200_VBI_PITCH_MASK);
484}
485
486/*************************************************************/
487/*  READ ROUTINES  |  INCLUDED FOR DIAGNOSTIC PURPOSES ONLY  */
488/*************************************************************/
489
490#if GFX_READ_ROUTINES
491
492/*----------------------------------------------------------------------------
493 * gfx_get_vip_enable
494 *----------------------------------------------------------------------------
495 */
496#if GFX_VIP_DYNAMIC
497int
498sc1200_get_vip_enable(void)
499#else
500int
501gfx_get_vip_enable(void)
502#endif
503{
504    if (READ_VIP32(SC1200_VIP_CONTROL) & SC1200_VIP_DATA_CAPTURE_EN)
505        return (1);
506    return (0);
507}
508
509/*----------------------------------------------------------------------------
510 * gfx_get_vip_pitch
511 *----------------------------------------------------------------------------
512 */
513#if GFX_VIP_DYNAMIC
514unsigned long
515sc1200_get_vip_pitch(void)
516#else
517unsigned long
518gfx_get_vip_pitch(void)
519#endif
520{
521    return (READ_VIP32(SC1200_VIP_PITCH) & SC1200_VIP_PITCH_MASK);
522}
523
524/*----------------------------------------------------------------------------
525 * gfx_get_vip_mode
526 *----------------------------------------------------------------------------
527 */
528#if GFX_VIP_DYNAMIC
529int
530sc1200_get_vip_mode(void)
531#else
532int
533gfx_get_vip_mode(void)
534#endif
535{
536    switch (READ_VIP32(SC1200_VIP_CONFIG) & SC1200_VIP_MODE_MASK) {
537    case SC1200_VIP_MODE_C:
538        return VIP_MODE_C;
539    default:
540        return (0);
541    }
542}
543
544/*----------------------------------------------------------------------------
545 * gfx_get_vbi_enable
546 *----------------------------------------------------------------------------
547 */
548#if GFX_VIP_DYNAMIC
549int
550sc1200_get_vbi_enable(void)
551#else
552int
553gfx_get_vbi_enable(void)
554#endif
555{
556    if (READ_VIP32(SC1200_VIP_CONTROL) & SC1200_VIP_VBI_CAPTURE_EN)
557        return (1);
558    return (0);
559}
560
561/*----------------------------------------------------------------------------
562 * gfx_get_vbi_mode
563 *----------------------------------------------------------------------------
564 */
565#if GFX_VIP_DYNAMIC
566int
567sc1200_get_vbi_mode(void)
568#else
569int
570gfx_get_vbi_mode(void)
571#endif
572{
573    int config;
574    int mode = 0;
575
576    config =
577        (int) (READ_VIP32(SC1200_VIP_CONFIG) & (SC1200_VBI_ANCILLARY_TO_MEMORY
578                                                | SC1200_VBI_TASK_A_TO_MEMORY |
579                                                SC1200_VBI_TASK_B_TO_MEMORY));
580    if (config & SC1200_VBI_ANCILLARY_TO_MEMORY)
581        mode |= VBI_ANCILLARY;
582    if (config & SC1200_VBI_TASK_A_TO_MEMORY)
583        mode |= VBI_TASK_A;
584    if (config & SC1200_VBI_TASK_B_TO_MEMORY)
585        mode |= VBI_TASK_B;
586    return mode;
587}
588
589/*----------------------------------------------------------------------------
590 * gfx_get_vbi_base
591 *----------------------------------------------------------------------------
592 */
593#if GFX_VIP_DYNAMIC
594unsigned long
595sc1200_get_vbi_base(int odd)
596#else
597unsigned long
598gfx_get_vbi_base(int odd)
599#endif
600{
601    /* MASK BIT 23 AND ABOVE TO MAKE IT A TRUE OFFSET */
602
603    if (odd)
604        return (READ_VIP32(SC1200_VBI_ODD_BASE));
605    return (READ_VIP32(SC1200_VBI_EVEN_BASE));
606}
607
608/*----------------------------------------------------------------------------
609 * gfx_get_vbi_direct
610 *----------------------------------------------------------------------------
611 */
612#if GFX_VIP_DYNAMIC
613unsigned long
614sc1200_get_vbi_direct(int odd)
615#else
616unsigned long
617gfx_get_vbi_direct(int odd)
618#endif
619{
620    /* MASK BIT 23 AND ABOVE TO MAKE IT A TRUE OFFSET */
621
622    if (odd)
623        return (READ_VIP32(SC1200_ODD_DIRECT_VBI_LINE_ENABLE) &
624                SC1200_DIRECT_VBI_LINE_ENABLE_MASK);
625    return (READ_VIP32(SC1200_EVEN_DIRECT_VBI_LINE_ENABLE) &
626            SC1200_DIRECT_VBI_LINE_ENABLE_MASK);
627}
628
629/*---------------------------------------------------------------------------
630 * gfx_get_vbi_interrupt
631 *----------------------------------------------------------------------------
632 */
633#if GFX_VIP_DYNAMIC
634int
635sc1200_get_vbi_interrupt(void)
636#else
637int
638gfx_get_vbi_interrupt(void)
639#endif
640{
641    if (READ_VIP32(SC1200_VIP_CONTROL) & SC1200_VIP_VBI_FIELD_INTERRUPT_EN)
642        return (1);
643    return (0);
644}
645
646/*----------------------------------------------------------------------------
647 * gfx_get_vip_bus_request_threshold_high
648 *----------------------------------------------------------------------------
649 */
650#if GFX_VIP_DYNAMIC
651int
652sc1200_get_vip_bus_request_threshold_high(void)
653#else
654int
655gfx_get_vip_bus_request_threshold_high(void)
656#endif
657{
658    if (READ_VIP32(SC1200_VIP_CONFIG) & SC1200_VIP_BUS_REQUEST_THRESHOLD)
659        return (1);
660    return (0);
661}
662
663#endif                          /* GFX_READ_ROUTINES */
664
665/* END OF FILE */
666