162306a36Sopenharmony_ci/* 262306a36Sopenharmony_ci * linux/drivers/video/bt431.h 362306a36Sopenharmony_ci * 462306a36Sopenharmony_ci * Copyright 2003 Thiemo Seufer <seufer@csv.ica.uni-stuttgart.de> 562306a36Sopenharmony_ci * Copyright 2016 Maciej W. Rozycki <macro@linux-mips.org> 662306a36Sopenharmony_ci * 762306a36Sopenharmony_ci * This file is subject to the terms and conditions of the GNU General 862306a36Sopenharmony_ci * Public License. See the file COPYING in the main directory of this 962306a36Sopenharmony_ci * archive for more details. 1062306a36Sopenharmony_ci */ 1162306a36Sopenharmony_ci#include <linux/types.h> 1262306a36Sopenharmony_ci 1362306a36Sopenharmony_ci#define BT431_CURSOR_SIZE 64 1462306a36Sopenharmony_ci 1562306a36Sopenharmony_ci/* 1662306a36Sopenharmony_ci * Bt431 cursor generator registers, 32-bit aligned. 1762306a36Sopenharmony_ci * Two twin Bt431 are used on the DECstation's PMAG-AA. 1862306a36Sopenharmony_ci */ 1962306a36Sopenharmony_cistruct bt431_regs { 2062306a36Sopenharmony_ci volatile u16 addr_lo; 2162306a36Sopenharmony_ci u16 pad0; 2262306a36Sopenharmony_ci volatile u16 addr_hi; 2362306a36Sopenharmony_ci u16 pad1; 2462306a36Sopenharmony_ci volatile u16 addr_cmap; 2562306a36Sopenharmony_ci u16 pad2; 2662306a36Sopenharmony_ci volatile u16 addr_reg; 2762306a36Sopenharmony_ci u16 pad3; 2862306a36Sopenharmony_ci}; 2962306a36Sopenharmony_ci 3062306a36Sopenharmony_cistatic inline u16 bt431_set_value(u8 val) 3162306a36Sopenharmony_ci{ 3262306a36Sopenharmony_ci return ((val << 8) | (val & 0xff)) & 0xffff; 3362306a36Sopenharmony_ci} 3462306a36Sopenharmony_ci 3562306a36Sopenharmony_cistatic inline u8 bt431_get_value(u16 val) 3662306a36Sopenharmony_ci{ 3762306a36Sopenharmony_ci return val & 0xff; 3862306a36Sopenharmony_ci} 3962306a36Sopenharmony_ci 4062306a36Sopenharmony_ci/* 4162306a36Sopenharmony_ci * Additional registers addressed indirectly. 4262306a36Sopenharmony_ci */ 4362306a36Sopenharmony_ci#define BT431_REG_CMD 0x0000 4462306a36Sopenharmony_ci#define BT431_REG_CXLO 0x0001 4562306a36Sopenharmony_ci#define BT431_REG_CXHI 0x0002 4662306a36Sopenharmony_ci#define BT431_REG_CYLO 0x0003 4762306a36Sopenharmony_ci#define BT431_REG_CYHI 0x0004 4862306a36Sopenharmony_ci#define BT431_REG_WXLO 0x0005 4962306a36Sopenharmony_ci#define BT431_REG_WXHI 0x0006 5062306a36Sopenharmony_ci#define BT431_REG_WYLO 0x0007 5162306a36Sopenharmony_ci#define BT431_REG_WYHI 0x0008 5262306a36Sopenharmony_ci#define BT431_REG_WWLO 0x0009 5362306a36Sopenharmony_ci#define BT431_REG_WWHI 0x000a 5462306a36Sopenharmony_ci#define BT431_REG_WHLO 0x000b 5562306a36Sopenharmony_ci#define BT431_REG_WHHI 0x000c 5662306a36Sopenharmony_ci 5762306a36Sopenharmony_ci#define BT431_REG_CRAM_BASE 0x0000 5862306a36Sopenharmony_ci#define BT431_REG_CRAM_END 0x01ff 5962306a36Sopenharmony_ci 6062306a36Sopenharmony_ci/* 6162306a36Sopenharmony_ci * Command register. 6262306a36Sopenharmony_ci */ 6362306a36Sopenharmony_ci#define BT431_CMD_CURS_ENABLE 0x40 6462306a36Sopenharmony_ci#define BT431_CMD_XHAIR_ENABLE 0x20 6562306a36Sopenharmony_ci#define BT431_CMD_OR_CURSORS 0x10 6662306a36Sopenharmony_ci#define BT431_CMD_XOR_CURSORS 0x00 6762306a36Sopenharmony_ci#define BT431_CMD_1_1_MUX 0x00 6862306a36Sopenharmony_ci#define BT431_CMD_4_1_MUX 0x04 6962306a36Sopenharmony_ci#define BT431_CMD_5_1_MUX 0x08 7062306a36Sopenharmony_ci#define BT431_CMD_xxx_MUX 0x0c 7162306a36Sopenharmony_ci#define BT431_CMD_THICK_1 0x00 7262306a36Sopenharmony_ci#define BT431_CMD_THICK_3 0x01 7362306a36Sopenharmony_ci#define BT431_CMD_THICK_5 0x02 7462306a36Sopenharmony_ci#define BT431_CMD_THICK_7 0x03 7562306a36Sopenharmony_ci 7662306a36Sopenharmony_cistatic inline void bt431_select_reg(struct bt431_regs *regs, int ir) 7762306a36Sopenharmony_ci{ 7862306a36Sopenharmony_ci /* 7962306a36Sopenharmony_ci * The compiler splits the write in two bytes without these 8062306a36Sopenharmony_ci * helper variables. 8162306a36Sopenharmony_ci */ 8262306a36Sopenharmony_ci volatile u16 *lo = &(regs->addr_lo); 8362306a36Sopenharmony_ci volatile u16 *hi = &(regs->addr_hi); 8462306a36Sopenharmony_ci 8562306a36Sopenharmony_ci mb(); 8662306a36Sopenharmony_ci *lo = bt431_set_value(ir & 0xff); 8762306a36Sopenharmony_ci wmb(); 8862306a36Sopenharmony_ci *hi = bt431_set_value((ir >> 8) & 0xff); 8962306a36Sopenharmony_ci} 9062306a36Sopenharmony_ci 9162306a36Sopenharmony_ci/* Autoincrement read/write. */ 9262306a36Sopenharmony_cistatic inline u8 bt431_read_reg_inc(struct bt431_regs *regs) 9362306a36Sopenharmony_ci{ 9462306a36Sopenharmony_ci /* 9562306a36Sopenharmony_ci * The compiler splits the write in two bytes without the 9662306a36Sopenharmony_ci * helper variable. 9762306a36Sopenharmony_ci */ 9862306a36Sopenharmony_ci volatile u16 *r = &(regs->addr_reg); 9962306a36Sopenharmony_ci 10062306a36Sopenharmony_ci mb(); 10162306a36Sopenharmony_ci return bt431_get_value(*r); 10262306a36Sopenharmony_ci} 10362306a36Sopenharmony_ci 10462306a36Sopenharmony_cistatic inline void bt431_write_reg_inc(struct bt431_regs *regs, u8 value) 10562306a36Sopenharmony_ci{ 10662306a36Sopenharmony_ci /* 10762306a36Sopenharmony_ci * The compiler splits the write in two bytes without the 10862306a36Sopenharmony_ci * helper variable. 10962306a36Sopenharmony_ci */ 11062306a36Sopenharmony_ci volatile u16 *r = &(regs->addr_reg); 11162306a36Sopenharmony_ci 11262306a36Sopenharmony_ci mb(); 11362306a36Sopenharmony_ci *r = bt431_set_value(value); 11462306a36Sopenharmony_ci} 11562306a36Sopenharmony_ci 11662306a36Sopenharmony_cistatic inline u8 bt431_read_reg(struct bt431_regs *regs, int ir) 11762306a36Sopenharmony_ci{ 11862306a36Sopenharmony_ci bt431_select_reg(regs, ir); 11962306a36Sopenharmony_ci return bt431_read_reg_inc(regs); 12062306a36Sopenharmony_ci} 12162306a36Sopenharmony_ci 12262306a36Sopenharmony_cistatic inline void bt431_write_reg(struct bt431_regs *regs, int ir, u8 value) 12362306a36Sopenharmony_ci{ 12462306a36Sopenharmony_ci bt431_select_reg(regs, ir); 12562306a36Sopenharmony_ci bt431_write_reg_inc(regs, value); 12662306a36Sopenharmony_ci} 12762306a36Sopenharmony_ci 12862306a36Sopenharmony_ci/* Autoincremented read/write for the cursor map. */ 12962306a36Sopenharmony_cistatic inline u16 bt431_read_cmap_inc(struct bt431_regs *regs) 13062306a36Sopenharmony_ci{ 13162306a36Sopenharmony_ci /* 13262306a36Sopenharmony_ci * The compiler splits the write in two bytes without the 13362306a36Sopenharmony_ci * helper variable. 13462306a36Sopenharmony_ci */ 13562306a36Sopenharmony_ci volatile u16 *r = &(regs->addr_cmap); 13662306a36Sopenharmony_ci 13762306a36Sopenharmony_ci mb(); 13862306a36Sopenharmony_ci return *r; 13962306a36Sopenharmony_ci} 14062306a36Sopenharmony_ci 14162306a36Sopenharmony_cistatic inline void bt431_write_cmap_inc(struct bt431_regs *regs, u16 value) 14262306a36Sopenharmony_ci{ 14362306a36Sopenharmony_ci /* 14462306a36Sopenharmony_ci * The compiler splits the write in two bytes without the 14562306a36Sopenharmony_ci * helper variable. 14662306a36Sopenharmony_ci */ 14762306a36Sopenharmony_ci volatile u16 *r = &(regs->addr_cmap); 14862306a36Sopenharmony_ci 14962306a36Sopenharmony_ci mb(); 15062306a36Sopenharmony_ci *r = value; 15162306a36Sopenharmony_ci} 15262306a36Sopenharmony_ci 15362306a36Sopenharmony_cistatic inline u16 bt431_read_cmap(struct bt431_regs *regs, int cr) 15462306a36Sopenharmony_ci{ 15562306a36Sopenharmony_ci bt431_select_reg(regs, cr); 15662306a36Sopenharmony_ci return bt431_read_cmap_inc(regs); 15762306a36Sopenharmony_ci} 15862306a36Sopenharmony_ci 15962306a36Sopenharmony_cistatic inline void bt431_write_cmap(struct bt431_regs *regs, int cr, u16 value) 16062306a36Sopenharmony_ci{ 16162306a36Sopenharmony_ci bt431_select_reg(regs, cr); 16262306a36Sopenharmony_ci bt431_write_cmap_inc(regs, value); 16362306a36Sopenharmony_ci} 16462306a36Sopenharmony_ci 16562306a36Sopenharmony_cistatic inline void bt431_enable_cursor(struct bt431_regs *regs) 16662306a36Sopenharmony_ci{ 16762306a36Sopenharmony_ci bt431_write_reg(regs, BT431_REG_CMD, 16862306a36Sopenharmony_ci BT431_CMD_CURS_ENABLE | BT431_CMD_OR_CURSORS 16962306a36Sopenharmony_ci | BT431_CMD_4_1_MUX | BT431_CMD_THICK_1); 17062306a36Sopenharmony_ci} 17162306a36Sopenharmony_ci 17262306a36Sopenharmony_cistatic inline void bt431_erase_cursor(struct bt431_regs *regs) 17362306a36Sopenharmony_ci{ 17462306a36Sopenharmony_ci bt431_write_reg(regs, BT431_REG_CMD, BT431_CMD_4_1_MUX); 17562306a36Sopenharmony_ci} 17662306a36Sopenharmony_ci 17762306a36Sopenharmony_cistatic inline void bt431_position_cursor(struct bt431_regs *regs, u16 x, u16 y) 17862306a36Sopenharmony_ci{ 17962306a36Sopenharmony_ci /* 18062306a36Sopenharmony_ci * Magic from the MACH sources. 18162306a36Sopenharmony_ci * 18262306a36Sopenharmony_ci * Cx = x + D + H - P 18362306a36Sopenharmony_ci * P = 37 if 1:1, 52 if 4:1, 57 if 5:1 18462306a36Sopenharmony_ci * D = pixel skew between outdata and external data 18562306a36Sopenharmony_ci * H = pixels between HSYNCH falling and active video 18662306a36Sopenharmony_ci * 18762306a36Sopenharmony_ci * Cy = y + V - 32 18862306a36Sopenharmony_ci * V = scanlines between HSYNCH falling, two or more 18962306a36Sopenharmony_ci * clocks after VSYNCH falling, and active video 19062306a36Sopenharmony_ci */ 19162306a36Sopenharmony_ci x += 412 - 52; 19262306a36Sopenharmony_ci y += 68 - 32; 19362306a36Sopenharmony_ci 19462306a36Sopenharmony_ci /* Use autoincrement. */ 19562306a36Sopenharmony_ci bt431_select_reg(regs, BT431_REG_CXLO); 19662306a36Sopenharmony_ci bt431_write_reg_inc(regs, x & 0xff); /* BT431_REG_CXLO */ 19762306a36Sopenharmony_ci bt431_write_reg_inc(regs, (x >> 8) & 0x0f); /* BT431_REG_CXHI */ 19862306a36Sopenharmony_ci bt431_write_reg_inc(regs, y & 0xff); /* BT431_REG_CYLO */ 19962306a36Sopenharmony_ci bt431_write_reg_inc(regs, (y >> 8) & 0x0f); /* BT431_REG_CYHI */ 20062306a36Sopenharmony_ci} 20162306a36Sopenharmony_ci 20262306a36Sopenharmony_cistatic inline void bt431_set_cursor(struct bt431_regs *regs, 20362306a36Sopenharmony_ci const char *data, const char *mask, 20462306a36Sopenharmony_ci u16 rop, u16 width, u16 height) 20562306a36Sopenharmony_ci{ 20662306a36Sopenharmony_ci u16 x, y; 20762306a36Sopenharmony_ci int i; 20862306a36Sopenharmony_ci 20962306a36Sopenharmony_ci i = 0; 21062306a36Sopenharmony_ci width = DIV_ROUND_UP(width, 8); 21162306a36Sopenharmony_ci bt431_select_reg(regs, BT431_REG_CRAM_BASE); 21262306a36Sopenharmony_ci for (y = 0; y < BT431_CURSOR_SIZE; y++) 21362306a36Sopenharmony_ci for (x = 0; x < BT431_CURSOR_SIZE / 8; x++) { 21462306a36Sopenharmony_ci u16 val = 0; 21562306a36Sopenharmony_ci 21662306a36Sopenharmony_ci if (y < height && x < width) { 21762306a36Sopenharmony_ci val = mask[i]; 21862306a36Sopenharmony_ci if (rop == ROP_XOR) 21962306a36Sopenharmony_ci val = (val << 8) | (val ^ data[i]); 22062306a36Sopenharmony_ci else 22162306a36Sopenharmony_ci val = (val << 8) | (val & data[i]); 22262306a36Sopenharmony_ci i++; 22362306a36Sopenharmony_ci } 22462306a36Sopenharmony_ci bt431_write_cmap_inc(regs, val); 22562306a36Sopenharmony_ci } 22662306a36Sopenharmony_ci} 22762306a36Sopenharmony_ci 22862306a36Sopenharmony_cistatic inline void bt431_init_cursor(struct bt431_regs *regs) 22962306a36Sopenharmony_ci{ 23062306a36Sopenharmony_ci /* no crosshair window */ 23162306a36Sopenharmony_ci bt431_select_reg(regs, BT431_REG_WXLO); 23262306a36Sopenharmony_ci bt431_write_reg_inc(regs, 0x00); /* BT431_REG_WXLO */ 23362306a36Sopenharmony_ci bt431_write_reg_inc(regs, 0x00); /* BT431_REG_WXHI */ 23462306a36Sopenharmony_ci bt431_write_reg_inc(regs, 0x00); /* BT431_REG_WYLO */ 23562306a36Sopenharmony_ci bt431_write_reg_inc(regs, 0x00); /* BT431_REG_WYHI */ 23662306a36Sopenharmony_ci bt431_write_reg_inc(regs, 0x00); /* BT431_REG_WWLO */ 23762306a36Sopenharmony_ci bt431_write_reg_inc(regs, 0x00); /* BT431_REG_WWHI */ 23862306a36Sopenharmony_ci bt431_write_reg_inc(regs, 0x00); /* BT431_REG_WHLO */ 23962306a36Sopenharmony_ci bt431_write_reg_inc(regs, 0x00); /* BT431_REG_WHHI */ 24062306a36Sopenharmony_ci} 241