Back to home page

OSCL-LXR

 
 

    


0001 /*
0002  *  linux/drivers/video/bt431.h
0003  *
0004  *  Copyright 2003  Thiemo Seufer <seufer@csv.ica.uni-stuttgart.de>
0005  *  Copyright 2016  Maciej W. Rozycki <macro@linux-mips.org>
0006  *
0007  *  This file is subject to the terms and conditions of the GNU General
0008  *  Public License. See the file COPYING in the main directory of this
0009  *  archive for more details.
0010  */
0011 #include <linux/types.h>
0012 
0013 #define BT431_CURSOR_SIZE   64
0014 
0015 /*
0016  * Bt431 cursor generator registers, 32-bit aligned.
0017  * Two twin Bt431 are used on the DECstation's PMAG-AA.
0018  */
0019 struct bt431_regs {
0020     volatile u16 addr_lo;
0021     u16 pad0;
0022     volatile u16 addr_hi;
0023     u16 pad1;
0024     volatile u16 addr_cmap;
0025     u16 pad2;
0026     volatile u16 addr_reg;
0027     u16 pad3;
0028 };
0029 
0030 static inline u16 bt431_set_value(u8 val)
0031 {
0032     return ((val << 8) | (val & 0xff)) & 0xffff;
0033 }
0034 
0035 static inline u8 bt431_get_value(u16 val)
0036 {
0037     return val & 0xff;
0038 }
0039 
0040 /*
0041  * Additional registers addressed indirectly.
0042  */
0043 #define BT431_REG_CMD       0x0000
0044 #define BT431_REG_CXLO      0x0001
0045 #define BT431_REG_CXHI      0x0002
0046 #define BT431_REG_CYLO      0x0003
0047 #define BT431_REG_CYHI      0x0004
0048 #define BT431_REG_WXLO      0x0005
0049 #define BT431_REG_WXHI      0x0006
0050 #define BT431_REG_WYLO      0x0007
0051 #define BT431_REG_WYHI      0x0008
0052 #define BT431_REG_WWLO      0x0009
0053 #define BT431_REG_WWHI      0x000a
0054 #define BT431_REG_WHLO      0x000b
0055 #define BT431_REG_WHHI      0x000c
0056 
0057 #define BT431_REG_CRAM_BASE 0x0000
0058 #define BT431_REG_CRAM_END  0x01ff
0059 
0060 /*
0061  * Command register.
0062  */
0063 #define BT431_CMD_CURS_ENABLE   0x40
0064 #define BT431_CMD_XHAIR_ENABLE  0x20
0065 #define BT431_CMD_OR_CURSORS    0x10
0066 #define BT431_CMD_XOR_CURSORS   0x00
0067 #define BT431_CMD_1_1_MUX   0x00
0068 #define BT431_CMD_4_1_MUX   0x04
0069 #define BT431_CMD_5_1_MUX   0x08
0070 #define BT431_CMD_xxx_MUX   0x0c
0071 #define BT431_CMD_THICK_1   0x00
0072 #define BT431_CMD_THICK_3   0x01
0073 #define BT431_CMD_THICK_5   0x02
0074 #define BT431_CMD_THICK_7   0x03
0075 
0076 static inline void bt431_select_reg(struct bt431_regs *regs, int ir)
0077 {
0078     /*
0079      * The compiler splits the write in two bytes without these
0080      * helper variables.
0081      */
0082     volatile u16 *lo = &(regs->addr_lo);
0083     volatile u16 *hi = &(regs->addr_hi);
0084 
0085     mb();
0086     *lo = bt431_set_value(ir & 0xff);
0087     wmb();
0088     *hi = bt431_set_value((ir >> 8) & 0xff);
0089 }
0090 
0091 /* Autoincrement read/write. */
0092 static inline u8 bt431_read_reg_inc(struct bt431_regs *regs)
0093 {
0094     /*
0095      * The compiler splits the write in two bytes without the
0096      * helper variable.
0097      */
0098     volatile u16 *r = &(regs->addr_reg);
0099 
0100     mb();
0101     return bt431_get_value(*r);
0102 }
0103 
0104 static inline void bt431_write_reg_inc(struct bt431_regs *regs, u8 value)
0105 {
0106     /*
0107      * The compiler splits the write in two bytes without the
0108      * helper variable.
0109      */
0110     volatile u16 *r = &(regs->addr_reg);
0111 
0112     mb();
0113     *r = bt431_set_value(value);
0114 }
0115 
0116 static inline u8 bt431_read_reg(struct bt431_regs *regs, int ir)
0117 {
0118     bt431_select_reg(regs, ir);
0119     return bt431_read_reg_inc(regs);
0120 }
0121 
0122 static inline void bt431_write_reg(struct bt431_regs *regs, int ir, u8 value)
0123 {
0124     bt431_select_reg(regs, ir);
0125     bt431_write_reg_inc(regs, value);
0126 }
0127 
0128 /* Autoincremented read/write for the cursor map. */
0129 static inline u16 bt431_read_cmap_inc(struct bt431_regs *regs)
0130 {
0131     /*
0132      * The compiler splits the write in two bytes without the
0133      * helper variable.
0134      */
0135     volatile u16 *r = &(regs->addr_cmap);
0136 
0137     mb();
0138     return *r;
0139 }
0140 
0141 static inline void bt431_write_cmap_inc(struct bt431_regs *regs, u16 value)
0142 {
0143     /*
0144      * The compiler splits the write in two bytes without the
0145      * helper variable.
0146      */
0147     volatile u16 *r = &(regs->addr_cmap);
0148 
0149     mb();
0150     *r = value;
0151 }
0152 
0153 static inline u16 bt431_read_cmap(struct bt431_regs *regs, int cr)
0154 {
0155     bt431_select_reg(regs, cr);
0156     return bt431_read_cmap_inc(regs);
0157 }
0158 
0159 static inline void bt431_write_cmap(struct bt431_regs *regs, int cr, u16 value)
0160 {
0161     bt431_select_reg(regs, cr);
0162     bt431_write_cmap_inc(regs, value);
0163 }
0164 
0165 static inline void bt431_enable_cursor(struct bt431_regs *regs)
0166 {
0167     bt431_write_reg(regs, BT431_REG_CMD,
0168             BT431_CMD_CURS_ENABLE | BT431_CMD_OR_CURSORS
0169             | BT431_CMD_4_1_MUX | BT431_CMD_THICK_1);
0170 }
0171 
0172 static inline void bt431_erase_cursor(struct bt431_regs *regs)
0173 {
0174     bt431_write_reg(regs, BT431_REG_CMD, BT431_CMD_4_1_MUX);
0175 }
0176 
0177 static inline void bt431_position_cursor(struct bt431_regs *regs, u16 x, u16 y)
0178 {
0179     /*
0180      * Magic from the MACH sources.
0181      *
0182      * Cx = x + D + H - P
0183      *  P = 37 if 1:1, 52 if 4:1, 57 if 5:1
0184      *  D = pixel skew between outdata and external data
0185      *  H = pixels between HSYNCH falling and active video
0186      *
0187      * Cy = y + V - 32
0188      *  V = scanlines between HSYNCH falling, two or more
0189      *      clocks after VSYNCH falling, and active video
0190      */
0191     x += 412 - 52;
0192     y += 68 - 32;
0193 
0194     /* Use autoincrement. */
0195     bt431_select_reg(regs, BT431_REG_CXLO);
0196     bt431_write_reg_inc(regs, x & 0xff); /* BT431_REG_CXLO */
0197     bt431_write_reg_inc(regs, (x >> 8) & 0x0f); /* BT431_REG_CXHI */
0198     bt431_write_reg_inc(regs, y & 0xff); /* BT431_REG_CYLO */
0199     bt431_write_reg_inc(regs, (y >> 8) & 0x0f); /* BT431_REG_CYHI */
0200 }
0201 
0202 static inline void bt431_set_cursor(struct bt431_regs *regs,
0203                     const char *data, const char *mask,
0204                     u16 rop, u16 width, u16 height)
0205 {
0206     u16 x, y;
0207     int i;
0208 
0209     i = 0;
0210     width = DIV_ROUND_UP(width, 8);
0211     bt431_select_reg(regs, BT431_REG_CRAM_BASE);
0212     for (y = 0; y < BT431_CURSOR_SIZE; y++)
0213         for (x = 0; x < BT431_CURSOR_SIZE / 8; x++) {
0214             u16 val = 0;
0215 
0216             if (y < height && x < width) {
0217                 val = mask[i];
0218                 if (rop == ROP_XOR)
0219                     val = (val << 8) | (val ^ data[i]);
0220                 else
0221                     val = (val << 8) | (val & data[i]);
0222                 i++;
0223             }
0224             bt431_write_cmap_inc(regs, val);
0225         }
0226 }
0227 
0228 static inline void bt431_init_cursor(struct bt431_regs *regs)
0229 {
0230     /* no crosshair window */
0231     bt431_select_reg(regs, BT431_REG_WXLO);
0232     bt431_write_reg_inc(regs, 0x00); /* BT431_REG_WXLO */
0233     bt431_write_reg_inc(regs, 0x00); /* BT431_REG_WXHI */
0234     bt431_write_reg_inc(regs, 0x00); /* BT431_REG_WYLO */
0235     bt431_write_reg_inc(regs, 0x00); /* BT431_REG_WYHI */
0236     bt431_write_reg_inc(regs, 0x00); /* BT431_REG_WWLO */
0237     bt431_write_reg_inc(regs, 0x00); /* BT431_REG_WWHI */
0238     bt431_write_reg_inc(regs, 0x00); /* BT431_REG_WHLO */
0239     bt431_write_reg_inc(regs, 0x00); /* BT431_REG_WHHI */
0240 }