Back to home page

LXR

 
 

    


File indexing completed on 2025-05-11 08:22:49

0001 /*
0002  *  SED1356 Support for KIT637_V6 (CSB637)
0003  *
0004  *  Based upon code from MicroMonitor 1.17 from http://www.umonfw.com/
0005  *  which includes this notice:
0006  */
0007 
0008 /*
0009  **************************************************************************
0010  *  General notice:
0011  *  This code is part of a boot-monitor package developed as a generic base
0012  *  platform for embedded system designs.  As such, it is likely to be
0013  *  distributed to various projects beyond the control of the original
0014  *  author.  Please notify the author of any enhancements made or bugs found
0015  *  so that all may benefit from the changes.  In addition, notification back
0016  *  to the author will allow the new user to pick up changes that may have
0017  *  been made by other users after this version of the code was distributed.
0018  *
0019  *  Note1: the majority of this code was edited with 4-space tabs.
0020  *  Note2: as more and more contributions are accepted, the term "author"
0021  *         is becoming a mis-representation of credit.
0022  *
0023  *  Original author:    Ed Sutter
0024  *  Email:              esutter@alcatel-lucent.com
0025  *  Phone:              908-582-2351
0026  **************************************************************************
0027  *
0028  *  Ed Sutter has been informed that this code is being used in RTEMS.
0029  *
0030  *  This code was reformatted by Joel Sherrill from OAR Corporation and
0031  *  Fernando Nicodemos <fgnicodemos@terra.com.br> from NCB - Sistemas
0032  *  Embarcados Ltda. (Brazil) to be more compliant with RTEMS coding
0033  *  standards and to eliminate C++ style comments.
0034  */
0035 
0036 #include <bsp.h>
0037 
0038 #include <stdlib.h>
0039 #include <stdio.h>
0040 #include "sed1356.h"
0041 #include "font8x16.h"
0042 
0043 int mode900lq;
0044 long PIXELS_PER_ROW;
0045 long PIXELS_PER_COL;
0046 long COLS_PER_SCREEN;
0047 long ROWS_PER_SCREEN;
0048 long SED_HOR_PULSE_WIDTH_LCD;
0049 long SED_VER_PULSE_START_LCD;
0050 long SED_HOR_PULSE_START_LCD;
0051 long SED_HOR_NONDISP_LCD;
0052 long SED_VER_NONDISP_LCD;
0053 long SED_VER_PULSE_WIDTH_LCD;
0054 
0055 /* globals to keep track of foreground, background colors and x,y position */
0056 int sed_color_depth;    /* 4, 8 or 16 */
0057 int sed_fg_color;      /* 0 to 15, used as lookup into VGA color table */
0058 int sed_bg_color;      /* 0 to 15, used as lookup into VGA color table */
0059 int sed_col;        /* current column, 0 to COLS_PER_SCREEN - 1 */
0060 int sed_row;        /* current row, 0 to (ROWS_PER_SCREEN * 2) - 1 */
0061 int sed_disp_mode_crt;       /* CRT=1, LCD=0 */
0062 int sed135x_ok;
0063 int sed135x_tst;
0064 uint32_t sed_fb_offset;       /* current offset into frame buffer for sed_putchar */
0065 
0066 void sed_writechar(uint8_t c);
0067 void sed_scroll(void);
0068 
0069 #define SED_REG_BASE      0x30000000  /* *CS2 */
0070 #define SED_MEM_BASE      (SED_REG_BASE + 0x00200000)
0071 #define SED_STEP          1      /* 16-bit port on 16-bit boundry */
0072 
0073 #define SED_REG16(_x_)       *(volatile uint16_t *)((uint32_t)SED_REG_BASE + (((uint32_t)_x_ * SED_STEP) ^ 0))  /* Control/Status Registers, 16-bit mode */
0074 #define RD_FB16(_reg_,_val_)   ((_val_) = *((volatile uint16_t *)(((uint32_t)SED_MEM_BASE + ((uint32_t)(_reg_ * SED_STEP) ^ 0)))))
0075 #define WR_FB16(_reg_,_val_)   (*((volatile uint16_t *)(((uint32_t)SED_MEM_BASE + ((uint32_t)(_reg_ * SED_STEP)  ^ 0)))) = (_val_))
0076 
0077 #if 0
0078 #define SED1356_REG_LCD_HOR_DISP                 SED_REG16(0x32)
0079 #define SED1356_REG_LCD_HOR_NONDISP_and_START    SED_REG16(0x34)
0080 #define SED1356_REG_LCD_HOR_PULSE               SED_REG16(0x36)
0081 #define SED1356_REG_LCD_VER_DISP_HT_LO_and_HI      SED_REG16(0x38)
0082 #define SED1356_REG_LCD_VER_NONDISP_and_START      SED_REG16(0x3a)
0083 #define SED1356_REG_LCD_VER_PULSE                SED_REG16(0x3c)
0084 #define SED1356_REG_LCD_DISP_MODE_and_MISC      SED_REG16(0x40)
0085 #define SED1356_REG_LCD_DISP_START_LO_and_MID    SED_REG16(0x42)
0086 #define SED1356_REG_LCD_DISP_START_HI           SED_REG16(0x44)
0087 #define SED1356_REG_LCD_ADD_OFFSET_LO_and_HI    SED_REG16(0x46)
0088 #define SED1356_REG_LCD_PIXEL_PAN             SED_REG16(0x48)
0089 #define SED1356_REG_LCD_FIFO_THRESH_LO_and_HI    SED_REG16(0x4a)
0090 #endif
0091 
0092 
0093 #define H2SED(_x_)        (_x_)
0094 
0095 #define FB_SIZE (640 * 480)
0096 #define SED_ROW_SIZE(_depth_)        ((PIXELS_PER_ROW * _depth_) / 8)
0097 #define SED_FB_SIZE(_depth_)         (((PIXELS_PER_COL * PIXELS_PER_ROW) * _depth_) / 8)
0098 
0099 #define FONT_WIDTH    8
0100 #define FONT_HEIGHT   16
0101 
0102 #define SED_GET_ADD(_row_, _col_, _depth_) \
0103     (((((_row_ * PIXELS_PER_ROW) * FONT_HEIGHT) \
0104                                                                                           + (_col_ * FONT_WIDTH)) \
0105                                                                                           * _depth_) / 8)
0106 
0107 
0108 #define SED_GET_PHYS_ADD(_reg_) \
0109   (volatile unsigned long)(SED_MEM_BASE + ((_reg_ * SED_STEP) ^ 0))
0110 
0111 
0112 #include "sed1356_16bit.h"
0113 
0114 /* #define SED_DBG */
0115 int sed135x_tst = 0;
0116 
0117 void sed_write_frame_buffer(
0118   uint32_t i,
0119   uint16_t wr16
0120 )
0121 {
0122   WR_FB16(i, wr16);
0123 }
0124 
0125 int sed_frame_buffer_size(void)
0126 {
0127   return SED_FB_SIZE(sed_color_depth);
0128 }
0129 
0130 void sed_clr_row(int char_row)
0131 {
0132   unsigned long sed_mem_add;
0133   int i;
0134   uint16_t wr16;
0135 
0136   /* clear the desired row */
0137   sed_mem_add = SED_GET_ADD(char_row, 0, sed_color_depth);
0138 
0139 #ifdef SED_DBG
0140   sed135x_tst = 1;
0141   printf("SED Clear Row %d, FB Add 0x%08lx, CPU Add 0x%08lx.\n ", char_row, sed_mem_add, SED_GET_PHYS_ADD(sed_mem_add));
0142   sed135x_tst = 0;
0143 #endif
0144 
0145   switch (sed_color_depth)
0146   {
0147     case 4:
0148       wr16 = ((sed_bg_color << 12) | (sed_bg_color << 8) | (sed_bg_color << 4) | (sed_bg_color << 0));
0149 #ifdef SED_DBG
0150   sed135x_tst = 1;
0151   printf("SED Clear Row %d, FB Add 0x%08lx to 0x%08lx.\n ", char_row, sed_mem_add, sed_mem_add + ((PIXELS_PER_ROW * FONT_HEIGHT) / 2));
0152   sed135x_tst = 0;
0153 #endif
0154       for (i = 0; i < ((PIXELS_PER_ROW * FONT_HEIGHT) / 2); i += 2){
0155         WR_FB16(sed_mem_add, wr16);
0156         sed_mem_add += 2;
0157       } /* for font_row */
0158       break;
0159     case 8:
0160       wr16 = ((sed_bg_color << 8) | (sed_bg_color << 0));
0161       for (i = 0; i < (PIXELS_PER_ROW * FONT_HEIGHT); i += 2){
0162         WR_FB16(sed_mem_add, wr16);
0163         sed_mem_add += 2;
0164       } /* for font_row */
0165       break;
0166     case 16:
0167       wr16 = ((vga_lookup[sed_bg_color]));
0168       for (i = 0; i < ((PIXELS_PER_ROW * FONT_HEIGHT) * 2); i += 2){
0169         WR_FB16(sed_mem_add, wr16);
0170         sed_mem_add += 2;
0171       } /* for font_row */
0172       break;
0173   } /* switch sed_color_depth */
0174 } /* sed_clr_row */
0175 
0176 void sed_init(void)
0177 {
0178   mode900lq = 0;
0179   PIXELS_PER_ROW = 640;
0180   PIXELS_PER_COL = 480;
0181   COLS_PER_SCREEN = 80;
0182   ROWS_PER_SCREEN = 30;
0183   SED_HOR_PULSE_WIDTH_LCD = 0x0b;
0184   SED_HOR_NONDISP_LCD = 0x13;
0185   SED_VER_PULSE_WIDTH_LCD = 0x01;
0186   SED_VER_PULSE_START_LCD = 0x09;
0187   SED_VER_NONDISP_LCD = 0x2c;
0188 
0189   sed_color_depth = 16;          /* 16 => vga lookup */
0190   sed_fg_color = 14;             /* Bright Yellow */
0191   sed_bg_color = 1;              /* Blue */
0192   sed_disp_mode_crt = 0;         /* default to LCD */
0193   sed_fb_offset = 0x00;
0194   sed_row = 0;
0195   sed_col = 0;
0196 
0197   sed135x_ok = 1;
0198   sed135x_tst = 0;
0199   sed_clearscreen();
0200 }
0201 
0202 /*
0203  * sed_putchar()
0204  *
0205  * This routine parses the character and calls sed_writechar if it is a
0206  * printable character
0207  */
0208 void sed_putchar(char c)
0209 {
0210 
0211   if ((sed135x_ok == 0) || (sed135x_tst == 1)) return;
0212 
0213   /* First parse the character to see if it printable or an
0214    * acceptable control character.
0215    */
0216   switch (c) {
0217     case '\r':
0218       sed_col = 0;
0219       return;
0220     case '\n':
0221       sed_col = 0;
0222       sed_scroll();
0223       return;
0224     case '\b':
0225       sed_col--;
0226       if (sed_col < 0) {
0227         sed_row--;
0228         if (sed_row < 0)
0229           sed_row = 0;
0230         sed_col = COLS_PER_SCREEN - 1;
0231       }
0232       c = 0;    /* erase the character */
0233       sed_writechar(c);
0234       break;
0235     default:
0236       if (((uint8_t)c < FIRST_CHAR) || ((uint8_t)c > LAST_CHAR))
0237         return; /* drop anything we can't print */
0238       c -= FIRST_CHAR;  /* get aligned to the first printable character */
0239       sed_writechar(c);
0240       /* advance to next column */
0241       sed_col++;
0242       if (sed_col == COLS_PER_SCREEN) {
0243         sed_col = 0;
0244         sed_scroll();
0245       }
0246       break;
0247   }
0248 
0249 } /* sed_putchar() */
0250 
0251 /*
0252  * sed_writechar()
0253  *
0254  * This routine writes the character to the screen at the current cursor
0255  * location.
0256  */
0257 void sed_writechar(uint8_t c)
0258 {
0259   uint32_t sed_mem_add;
0260   int font_row, font_col;
0261   uint8_t font_data8;
0262   uint16_t wr16;
0263 
0264   /* Convert the current row,col and color depth values
0265    * into an address
0266    */
0267   sed_mem_add = SED_GET_ADD(sed_row, sed_col, sed_color_depth);
0268 
0269 #ifdef SED_DBG
0270   sed135x_tst = 1;
0271   printf("SED writechar at row %d, col %d, FB Add 0x%08lx, CPU Add 0x%08lx.\n ",    sed_row, sed_col, sed_mem_add, SED_GET_PHYS_ADD(sed_mem_add));
0272   sed135x_tst = 0;
0273 #endif
0274 
0275   if (FONT_WIDTH == 8) {
0276     switch (sed_color_depth) {
0277       case 4:
0278         /* Now render the font by painting one font row at a time */
0279         for (font_row = 0; font_row < FONT_HEIGHT; font_row++) {
0280           /* get the font row of data */
0281           font_data8 = font8x16[(c * FONT_HEIGHT) + font_row];
0282 
0283 
0284           for (font_col = 0; font_col < 8; font_col += 4)
0285           {
0286             /* get a words worth of pixels */
0287             wr16 = (((font_data8 & 0x80) ? sed_fg_color << 12 : sed_bg_color << 12)
0288                 | ((font_data8 & 0x40) ? sed_fg_color << 8 : sed_bg_color << 8)
0289                 | ((font_data8 & 0x20) ? sed_fg_color << 4 : sed_bg_color << 4)
0290                 | ((font_data8 & 0x10) ? sed_fg_color << 0 : sed_bg_color << 0));
0291             font_data8 = font_data8 << 4;
0292             WR_FB16(sed_mem_add, wr16);
0293             /* if we are in the 2nd frame buffer, write to the 1st
0294              * frame buffer also
0295              */
0296             if (sed_row > (ROWS_PER_SCREEN - 1)) {
0297               WR_FB16((sed_mem_add - SED_FB_SIZE(sed_color_depth)), wr16);
0298             }
0299             sed_mem_add += 2;
0300           } /* for font_col */
0301           /* go to the next pixel row */
0302           sed_mem_add += (SED_ROW_SIZE(sed_color_depth) - ((FONT_WIDTH * sed_color_depth) / 8));
0303         } /* for font_row */
0304         break;
0305 
0306       case 8:
0307         /* Now render the font by painting one font row at a time */
0308         for (font_row = 0; font_row < FONT_HEIGHT; font_row++) {
0309           /* get the font row of data */
0310           font_data8 = font8x16[(c * FONT_HEIGHT) + font_row];
0311           for (font_col = 0; font_col < 8; font_col += 2)
0312           {
0313             /* get a words worth of pixels */
0314             wr16 = (((font_data8 & 0x80) ? sed_fg_color << 8 : sed_bg_color << 8)
0315                 | ((font_data8 & 0x40) ? sed_fg_color << 0 : sed_bg_color << 0));
0316             font_data8 = font_data8 << 2;
0317             WR_FB16(sed_mem_add, wr16);
0318             /* if we are in the 2nd frame buffer, write to the 1st
0319              * frame buffer also
0320              */
0321             if (sed_row > (ROWS_PER_SCREEN - 1)) {
0322               WR_FB16((sed_mem_add - SED_FB_SIZE(sed_color_depth)), wr16);
0323             }
0324             sed_mem_add += 2;
0325           } /* for font_col */
0326           /* go to the next pixel row */
0327           sed_mem_add += (SED_ROW_SIZE(sed_color_depth) - ((FONT_WIDTH * sed_color_depth) / 8));
0328         } /* for font_row */
0329         break;
0330 
0331       case 16:
0332         /* Now render the font by painting one font row at a time */
0333         for (font_row = 0; font_row < FONT_HEIGHT; font_row++) {
0334           /* get the font row of data */
0335           font_data8 = font8x16[(c * FONT_HEIGHT) + font_row];
0336           for (font_col = 0; font_col < 8; font_col++)
0337           {
0338             /* get a words worth of pixels */
0339             wr16 = ((font_data8 & 0x80) ?
0340                      vga_lookup[sed_fg_color] : vga_lookup[sed_bg_color]);
0341             font_data8 = font_data8 << 1;
0342             WR_FB16(sed_mem_add, wr16);
0343             /* if we are in the 2nd frame buffer, write to the 1st
0344              * frame buffer also.
0345              */
0346             if (sed_row > (ROWS_PER_SCREEN - 1)) {
0347               WR_FB16((sed_mem_add - SED_FB_SIZE(sed_color_depth)), wr16);
0348             }
0349             sed_mem_add += 2;
0350           } /* for font_col */
0351           /* go to the next pixel row */
0352           sed_mem_add += (SED_ROW_SIZE(sed_color_depth) - ((FONT_WIDTH * sed_color_depth) / 8));
0353         } /* for font_row */
0354         break;
0355 
0356     } /* switch sed_color depth */
0357   } /* FONT_WIDTH == 8 */
0358   else
0359   {
0360     return;
0361   }
0362 } /* sed_writechar() */
0363 
0364 static void sed_update_fb_offset(void)
0365 {
0366   /* write the new sed_fb_offset value */
0367   if (sed_disp_mode_crt) {
0368   /* before we change the address offset, wait for the display to
0369    * go from active to non-active, unless the display is not enabled
0370    */
0371   if (SED1356_REG_DISP_MODE & H2SED(SED1356_DISP_MODE_CRT)) {  /* CRT is on */
0372     while ((SED1356_REG_CRT_VER_NONDISP_and_START & H2SED(SED1356_VER_NONDISP)) == 0) {}
0373     while ((SED1356_REG_CRT_VER_NONDISP_and_START & H2SED(SED1356_VER_NONDISP)) == 1) {}
0374     }
0375     SED1356_REG_CRT_DISP_START_LO_and_MID  = H2SED(((sed_fb_offset & 0x00ffff) >> 0));
0376     SED1356_REG_CRT_DISP_START_HI  = H2SED(((sed_fb_offset & 0x070000) >> 16));
0377   }
0378   else /* LCD */
0379   {
0380     if (SED1356_REG_DISP_MODE & H2SED(SED1356_DISP_MODE_LCD)) {  /* LCD is on */
0381       while ((SED1356_REG_LCD_VER_NONDISP_and_START & H2SED(SED1356_VER_NONDISP)) == 0) {}
0382       while ((SED1356_REG_LCD_VER_NONDISP_and_START & H2SED(SED1356_VER_NONDISP)) == 1) {}
0383     }
0384     SED1356_REG_LCD_DISP_START_LO_and_MID  = H2SED(((sed_fb_offset & 0x00ffff) >> 0));
0385     SED1356_REG_LCD_DISP_START_HI  = H2SED(((sed_fb_offset & 0x070000) >> 16));
0386   }
0387 }
0388 
0389 /* sed_scroll()
0390  *
0391  * Because we are most likely running out of FLASH and probably also with
0392  * cache disabled, a brute force memcpy of the whole screen would be very
0393  * slow, even with reduced color depths.  Instead, we define a frame buffer
0394  * that is twice the size of our actual display.  This does limit us to a
0395  * 1Mbyte active display size, but 640 x 480 @ 16-bits/pixel = 614K so it
0396  * works just fine.  800 x 600 can be had by reducing the color depth to
0397  * 8-bits/pixel and using the look up tables.
0398  *
0399  * With the double buffering, we always write to the first buffer, even
0400  * when the second buffer is active.  This allows us to scroll by adjusting
0401  * the starting and ending addresses in the SED135x by one row.  When we
0402  * reach the end of our virtual buffer, we reset the starting and ending
0403  * addresses to the first buffer.  Note that we can not adjust the SED135x
0404  * registers until it is in vertical retrace.  That means we have to wait
0405  * until it is in active display, then goes to non-display, unless the
0406  * screen is blanked, in which case we can update immediately.
0407  */
0408 void sed_scroll(void)
0409 {
0410   sed_row++;
0411 
0412   /* clear the new row(s) */
0413   sed_clr_row(sed_row);
0414   if (sed_row > (ROWS_PER_SCREEN - 1)) {
0415     sed_clr_row(sed_row - ROWS_PER_SCREEN);
0416   }
0417   /* when sed_y_pos is greater than ROWS_PER_SCREEN we just adjust the
0418    * start and end addresses in the SED135x.  If it is equal to 2 *
0419    * ROWS_PER_SCREEN, we reset the start and end addresses to SED_MEM_BASE.
0420    */
0421   if (sed_row > (ROWS_PER_SCREEN - 1)) {
0422     if (sed_row > ((ROWS_PER_SCREEN * 2) - 1)) {
0423       sed_fb_offset = 0x00;
0424       sed_row = 0;
0425       sed_clearscreen();
0426     } else {
0427       /* calculate the new offset address of the frame buffer in words */
0428       sed_fb_offset += (SED_GET_ADD(1, 0, sed_color_depth) / 2);
0429     }
0430     sed_update_fb_offset();
0431   } /* if (sed_row > (ROWS_PER_SCREEN - 1)) */
0432 }
0433 
0434 void sed_putstring(char *s)
0435 {
0436   char *p = s;
0437   while (*p)
0438     sed_putchar(*p++);
0439 }
0440 
0441 void sed_clearscreen(void)
0442 {
0443   int i;
0444   uint16_t wr16;
0445   int bg = sed_bg_color;
0446   int fbsize = sed_frame_buffer_size();
0447 
0448   /* we double buffer so clear ALL of memory */
0449   fbsize *= 2;
0450 
0451   /* fill the frame buffer with incrementing color values */
0452   switch (sed_color_depth){
0453     case 4:  wr16 = bg | bg << 4 | bg << 8 | bg << 12; break;
0454     case 8:  wr16 = bg | bg << 8; break;
0455     /* 16-bits bypasses the lookup table */
0456     default: wr16 = vga_lookup[bg]; break;
0457   }
0458   for (i = 0; i < fbsize; i += 2){
0459     sed_write_frame_buffer(i, wr16);
0460   }
0461 }