source: rtems/c/src/lib/libbsp/lm32/shared/milkymist_video/video.c @ dce1032b

4.11
Last change on this file since dce1032b was dce1032b, checked in by Joel Sherrill <joel.sherrill@…>, on Aug 1, 2011 at 1:48:40 PM

2011-08-01 Sebastien Bourdeauducq <sebastien.bourdeauducq@…>

PR 1869/bsps

  • startup/bspclean.c: New file.
  • include/tm27.h: Removed.
  • ChangeLog?, Makefile.am, README, preinstall.am, include/bsp.h, include/system_conf.h, make/custom/milkymist.cfg, startup/linkcmds: Complete BSP for Milkymist One supporting Milkymist SOC 1.0.x. Includes new or updated drivers for:
    • Multi-standard video input (PAL/SECAM/NTSC)
    • Two DMX512 (RS485) ports
    • MIDI IN and MIDI OUT ports
    • VGA output
    • AC'97 audio
    • NOR flash
    • 10/100 Ethernet
    • Memory card (experimental and incomplete)
    • USB host connectors (input devices only)
    • RC5 infrared receiver
    • RS232 debug port
  • Property mode set to 100644
File size: 7.5 KB
Line 
1/*  video.c
2 *
3 *  Milkymist video input driver for RTEMS
4 *
5 *  The license and distribution terms for this file may be
6 *  found in the file LICENSE in this distribution or at
7 *  http://www.rtems.com/license/LICENSE.
8 *
9 *  $Id$
10 *
11 *  COPYRIGHT (c) 2010, 2011 Sebastien Bourdeauducq
12 */
13
14#define RTEMS_STATUS_CHECKS_USE_PRINTK
15
16#include <stdlib.h>
17#include <stdio.h>
18#include <errno.h>
19#include <sys/types.h>
20#include <rtems.h>
21#include <bsp.h>
22#include <bsp/irq-generic.h>
23#include <rtems/libio.h>
24#include <rtems/status-checks.h>
25#include "../include/system_conf.h"
26#include "milkymist_video.h"
27
28#define DEVICE_NAME "/dev/video"
29#define N_BUFFERS 3
30#define FRAME_W 720
31#define FRAME_H 288
32
33static bool buffers_locked[N_BUFFERS];
34static void *buffers[N_BUFFERS];
35static int last_buffer;
36static int current_buffer;
37
38static rtems_isr frame_handler(rtems_vector_number n)
39{
40  int remaining_attempts;
41
42  lm32_interrupt_ack(1 << MM_IRQ_VIDEOIN);
43 
44  last_buffer = current_buffer;
45 
46  /* get a new buffer */
47  remaining_attempts = N_BUFFERS;
48  do {
49    current_buffer++;
50    if(current_buffer == N_BUFFERS)
51      current_buffer = 0;
52    remaining_attempts--;
53  } while(buffers_locked[current_buffer] && (remaining_attempts > 0));
54
55  MM_WRITE(MM_BT656_BASE, (unsigned int)buffers[current_buffer]);
56 
57  if(buffers_locked[current_buffer])
58    printk("Failed to find unlocked buffer\n");
59}
60
61static void i2c_delay(void)
62{
63  unsigned int i;
64
65  for(i=0;i<1000;i++) __asm__("nop");
66}
67
68/* I2C bit-banging functions from http://en.wikipedia.org/wiki/I2c */
69static unsigned int i2c_read_bit(void)
70{
71  unsigned int bit;
72
73  /* Let the slave drive data */
74  MM_WRITE(MM_BT656_I2C, 0);
75  i2c_delay();
76  MM_WRITE(MM_BT656_I2C, BT656_I2C_SDC);
77  i2c_delay();
78  bit = MM_READ(MM_BT656_I2C) & BT656_I2C_SDAIN;
79  i2c_delay();
80  MM_WRITE(MM_BT656_I2C, 0);
81  return bit;
82}
83
84static void i2c_write_bit(unsigned int bit)
85{
86  if(bit) {
87    MM_WRITE(MM_BT656_I2C, BT656_I2C_SDAOE|BT656_I2C_SDAOUT);
88  } else {
89    MM_WRITE(MM_BT656_I2C, BT656_I2C_SDAOE);
90  }
91  i2c_delay();
92  MM_WRITE(MM_BT656_I2C, MM_READ(MM_BT656_I2C) | BT656_I2C_SDC);
93  i2c_delay();
94  MM_WRITE(MM_BT656_I2C, MM_READ(MM_BT656_I2C) & ~BT656_I2C_SDC);
95}
96
97static int i2c_started;
98
99static void i2c_start_cond(void)
100{
101  if(i2c_started) {
102    /* set SDA to 1 */
103    MM_WRITE(MM_BT656_I2C, BT656_I2C_SDAOE|BT656_I2C_SDAOUT);
104    i2c_delay();
105    MM_WRITE(MM_BT656_I2C, MM_READ(MM_BT656_I2C) | BT656_I2C_SDC);
106  }
107  /* SCL is high, set SDA from 1 to 0 */
108  MM_WRITE(MM_BT656_I2C, BT656_I2C_SDAOE|BT656_I2C_SDC);
109  i2c_delay();
110  MM_WRITE(MM_BT656_I2C, BT656_I2C_SDAOE);
111  i2c_started = 1;
112}
113
114static void i2c_stop_cond(void)
115{
116  /* set SDA to 0 */
117  MM_WRITE(MM_BT656_I2C, BT656_I2C_SDAOE);
118  i2c_delay();
119  /* Clock stretching */
120  MM_WRITE(MM_BT656_I2C, BT656_I2C_SDAOE|BT656_I2C_SDC);
121  /* SCL is high, set SDA from 0 to 1 */
122  MM_WRITE(MM_BT656_I2C, BT656_I2C_SDC);
123  i2c_delay();
124  i2c_started = 0;
125}
126
127static unsigned int i2c_write(unsigned char byte)
128{
129  unsigned int bit;
130  unsigned int ack;
131
132  for(bit = 0; bit < 8; bit++) {
133    i2c_write_bit(byte & 0x80);
134    byte <<= 1;
135  }
136  ack = !i2c_read_bit();
137  return ack;
138}
139
140static unsigned char i2c_read(int ack)
141{
142  unsigned char byte = 0;
143  unsigned int bit;
144
145  for(bit = 0; bit < 8; bit++) {
146    byte <<= 1;
147    byte |= i2c_read_bit();
148  }
149  i2c_write_bit(!ack);
150  return byte;
151}
152
153static unsigned char read_reg(unsigned char addr)
154{
155  unsigned char r;
156
157  i2c_start_cond();
158  i2c_write(0x40);
159  i2c_write(addr);
160  i2c_start_cond();
161  i2c_write(0x41);
162  r = i2c_read(0);
163  i2c_stop_cond();
164
165  return r;
166}
167
168static void write_reg(unsigned char addr, unsigned char val)
169{
170  i2c_start_cond();
171  i2c_write(0x40);
172  i2c_write(addr);
173  i2c_write(val);
174  i2c_stop_cond();
175}
176
177static const char vreg_addr[] = {
178  0x1d, 0xc3, 0xc4
179};
180
181static const char vreg_dat[] = {
182  0x40, 0x05, 0x80
183};
184
185rtems_device_driver video_initialize(
186  rtems_device_major_number major,
187  rtems_device_minor_number minor,
188  void *arg
189)
190{
191  rtems_status_code sc;
192  rtems_isr_entry dummy;
193  int i;
194 
195  MM_WRITE(MM_BT656_I2C, BT656_I2C_SDC);
196
197  sc = rtems_io_register_name(DEVICE_NAME, major, 0);
198  RTEMS_CHECK_SC(sc, "create video input device");
199
200  rtems_interrupt_catch(frame_handler, MM_IRQ_VIDEOIN, &dummy);
201  bsp_interrupt_vector_enable(MM_IRQ_VIDEOIN);
202 
203  for(i=0;i<sizeof(vreg_addr);i++)
204    write_reg(vreg_addr[i], vreg_dat[i]);
205
206  return RTEMS_SUCCESSFUL;
207}
208
209rtems_device_driver video_open(
210  rtems_device_major_number major,
211  rtems_device_minor_number minor,
212  void *arg
213)
214{
215  int i;
216  int status;
217
218  for(i=0;i<N_BUFFERS;i++) {
219    status = posix_memalign(&buffers[i], 32, 2*FRAME_W*FRAME_H);
220    if(status != 0) {
221      i--;
222      while(i > 0) {
223        free(buffers[i]);
224        i--;
225      }
226      return RTEMS_UNSATISFIED;
227    }
228  }
229 
230  last_buffer = -1;
231  current_buffer = 0;
232 
233  MM_WRITE(MM_BT656_BASE, (unsigned int)buffers[current_buffer]);
234  MM_WRITE(MM_BT656_FILTERSTATUS, BT656_FILTER_FIELD1);
235 
236  return RTEMS_SUCCESSFUL;
237}
238
239rtems_device_driver video_close(
240  rtems_device_major_number major,
241  rtems_device_minor_number minor,
242  void *arg
243)
244{
245  int i;
246 
247  MM_WRITE(MM_BT656_FILTERSTATUS, 0);
248  while(MM_READ(MM_BT656_FILTERSTATUS) & BT656_FILTER_INFRAME);
249  for(i=0;i<N_BUFFERS;i++)
250    free(buffers[i]);
251  return RTEMS_SUCCESSFUL;
252}
253
254static void invalidate_caches(void)
255{
256  volatile char *flushbase = (char *)FMLBRG_FLUSH_BASE;
257  int i, offset;
258
259  offset = 0;
260  for (i=0;i<FMLBRG_LINE_COUNT;i++) {
261    flushbase[offset] = 0;
262    offset += FMLBRG_LINE_LENGTH;
263  }
264  __asm__ volatile( /* Invalidate Level-1 data cache */
265    "wcsr DCC, r0\n"
266    "nop\n"
267  );
268}
269
270rtems_device_driver video_control(
271  rtems_device_major_number major,
272  rtems_device_minor_number minor,
273  void *arg
274)
275{
276  rtems_libio_ioctl_args_t *args = arg;
277  unsigned int *a = (unsigned int *)args->buffer;
278  rtems_status_code sc;
279
280  switch (args->command) {
281    case VIDEO_BUFFER_LOCK:
282      if (last_buffer == -1) {
283        *a = 0;
284      } else {
285        bsp_interrupt_vector_disable(MM_IRQ_VIDEOIN);
286        if(*a) invalidate_caches();
287        *a = (unsigned int)buffers[last_buffer];
288        buffers_locked[last_buffer] = true;
289        bsp_interrupt_vector_enable(MM_IRQ_VIDEOIN);
290      }
291      sc = RTEMS_SUCCESSFUL;
292      break;
293    case VIDEO_BUFFER_UNLOCK: {
294      int i;
295      for(i=0;i<N_BUFFERS;i++) {
296        if ((unsigned int)buffers[i] == (unsigned int)a) {
297          buffers_locked[i] = false;
298          break;
299        }
300      }
301      sc = RTEMS_SUCCESSFUL;
302      break;
303    }
304   
305    case VIDEO_SET_BRIGHTNESS:
306      write_reg(0x0a, (unsigned int)a);
307      sc = RTEMS_SUCCESSFUL;
308      break;
309    case VIDEO_GET_BRIGHTNESS:
310      *a = read_reg(0x0a);
311      sc = RTEMS_SUCCESSFUL;
312      break;
313    case VIDEO_SET_CONTRAST:
314      write_reg(0x08, (unsigned int)a);
315      sc = RTEMS_SUCCESSFUL;
316      break;
317    case VIDEO_GET_CONTRAST:
318      *a = read_reg(0x08);
319      sc = RTEMS_SUCCESSFUL;
320      break;
321    case VIDEO_SET_HUE:
322      write_reg(0x0b, (unsigned int)a);
323      sc = RTEMS_SUCCESSFUL;
324      break;
325    case VIDEO_GET_HUE:
326      *a = read_reg(0x0b);
327      sc = RTEMS_SUCCESSFUL;
328      break;
329   
330    case VIDEO_GET_SIGNAL:
331      *a = read_reg(0x10);
332      sc = RTEMS_SUCCESSFUL;
333      break;
334   
335    case VIDEO_SET_REGISTER:
336      write_reg(((unsigned int )a & 0xffff0000) >> 16,
337        (unsigned int)a & 0x0000ffff);
338      sc = RTEMS_SUCCESSFUL;
339      break;
340    case VIDEO_GET_REGISTER:
341      *a = read_reg(*a);
342      sc = RTEMS_SUCCESSFUL;
343      break;
344   
345    default:
346      sc = RTEMS_UNSATISFIED;
347      break;
348  }
349
350  if (sc == RTEMS_SUCCESSFUL)
351    args->ioctl_return = 0;
352  else
353    args->ioctl_return = -1;
354
355  return sc;
356}
Note: See TracBrowser for help on using the repository browser.