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

5
Last change on this file since db46b5f8 was db46b5f8, checked in by Joel Sherrill <joel@…>, on 04/05/17 at 16:17:17

lm32/shared/milkymist_video/video.c: Include <rtems/bspIo.h>

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