18c2ecf20Sopenharmony_ci/*
28c2ecf20Sopenharmony_ci *	linux/drivers/video/bt431.h
38c2ecf20Sopenharmony_ci *
48c2ecf20Sopenharmony_ci *	Copyright 2003  Thiemo Seufer <seufer@csv.ica.uni-stuttgart.de>
58c2ecf20Sopenharmony_ci *	Copyright 2016  Maciej W. Rozycki <macro@linux-mips.org>
68c2ecf20Sopenharmony_ci *
78c2ecf20Sopenharmony_ci *	This file is subject to the terms and conditions of the GNU General
88c2ecf20Sopenharmony_ci *	Public License. See the file COPYING in the main directory of this
98c2ecf20Sopenharmony_ci *	archive for more details.
108c2ecf20Sopenharmony_ci */
118c2ecf20Sopenharmony_ci#include <linux/types.h>
128c2ecf20Sopenharmony_ci
138c2ecf20Sopenharmony_ci#define BT431_CURSOR_SIZE	64
148c2ecf20Sopenharmony_ci
158c2ecf20Sopenharmony_ci/*
168c2ecf20Sopenharmony_ci * Bt431 cursor generator registers, 32-bit aligned.
178c2ecf20Sopenharmony_ci * Two twin Bt431 are used on the DECstation's PMAG-AA.
188c2ecf20Sopenharmony_ci */
198c2ecf20Sopenharmony_cistruct bt431_regs {
208c2ecf20Sopenharmony_ci	volatile u16 addr_lo;
218c2ecf20Sopenharmony_ci	u16 pad0;
228c2ecf20Sopenharmony_ci	volatile u16 addr_hi;
238c2ecf20Sopenharmony_ci	u16 pad1;
248c2ecf20Sopenharmony_ci	volatile u16 addr_cmap;
258c2ecf20Sopenharmony_ci	u16 pad2;
268c2ecf20Sopenharmony_ci	volatile u16 addr_reg;
278c2ecf20Sopenharmony_ci	u16 pad3;
288c2ecf20Sopenharmony_ci};
298c2ecf20Sopenharmony_ci
308c2ecf20Sopenharmony_cistatic inline u16 bt431_set_value(u8 val)
318c2ecf20Sopenharmony_ci{
328c2ecf20Sopenharmony_ci	return ((val << 8) | (val & 0xff)) & 0xffff;
338c2ecf20Sopenharmony_ci}
348c2ecf20Sopenharmony_ci
358c2ecf20Sopenharmony_cistatic inline u8 bt431_get_value(u16 val)
368c2ecf20Sopenharmony_ci{
378c2ecf20Sopenharmony_ci	return val & 0xff;
388c2ecf20Sopenharmony_ci}
398c2ecf20Sopenharmony_ci
408c2ecf20Sopenharmony_ci/*
418c2ecf20Sopenharmony_ci * Additional registers addressed indirectly.
428c2ecf20Sopenharmony_ci */
438c2ecf20Sopenharmony_ci#define BT431_REG_CMD		0x0000
448c2ecf20Sopenharmony_ci#define BT431_REG_CXLO		0x0001
458c2ecf20Sopenharmony_ci#define BT431_REG_CXHI		0x0002
468c2ecf20Sopenharmony_ci#define BT431_REG_CYLO		0x0003
478c2ecf20Sopenharmony_ci#define BT431_REG_CYHI		0x0004
488c2ecf20Sopenharmony_ci#define BT431_REG_WXLO		0x0005
498c2ecf20Sopenharmony_ci#define BT431_REG_WXHI		0x0006
508c2ecf20Sopenharmony_ci#define BT431_REG_WYLO		0x0007
518c2ecf20Sopenharmony_ci#define BT431_REG_WYHI		0x0008
528c2ecf20Sopenharmony_ci#define BT431_REG_WWLO		0x0009
538c2ecf20Sopenharmony_ci#define BT431_REG_WWHI		0x000a
548c2ecf20Sopenharmony_ci#define BT431_REG_WHLO		0x000b
558c2ecf20Sopenharmony_ci#define BT431_REG_WHHI		0x000c
568c2ecf20Sopenharmony_ci
578c2ecf20Sopenharmony_ci#define BT431_REG_CRAM_BASE	0x0000
588c2ecf20Sopenharmony_ci#define BT431_REG_CRAM_END	0x01ff
598c2ecf20Sopenharmony_ci
608c2ecf20Sopenharmony_ci/*
618c2ecf20Sopenharmony_ci * Command register.
628c2ecf20Sopenharmony_ci */
638c2ecf20Sopenharmony_ci#define BT431_CMD_CURS_ENABLE	0x40
648c2ecf20Sopenharmony_ci#define BT431_CMD_XHAIR_ENABLE	0x20
658c2ecf20Sopenharmony_ci#define BT431_CMD_OR_CURSORS	0x10
668c2ecf20Sopenharmony_ci#define BT431_CMD_XOR_CURSORS	0x00
678c2ecf20Sopenharmony_ci#define BT431_CMD_1_1_MUX	0x00
688c2ecf20Sopenharmony_ci#define BT431_CMD_4_1_MUX	0x04
698c2ecf20Sopenharmony_ci#define BT431_CMD_5_1_MUX	0x08
708c2ecf20Sopenharmony_ci#define BT431_CMD_xxx_MUX	0x0c
718c2ecf20Sopenharmony_ci#define BT431_CMD_THICK_1	0x00
728c2ecf20Sopenharmony_ci#define BT431_CMD_THICK_3	0x01
738c2ecf20Sopenharmony_ci#define BT431_CMD_THICK_5	0x02
748c2ecf20Sopenharmony_ci#define BT431_CMD_THICK_7	0x03
758c2ecf20Sopenharmony_ci
768c2ecf20Sopenharmony_cistatic inline void bt431_select_reg(struct bt431_regs *regs, int ir)
778c2ecf20Sopenharmony_ci{
788c2ecf20Sopenharmony_ci	/*
798c2ecf20Sopenharmony_ci	 * The compiler splits the write in two bytes without these
808c2ecf20Sopenharmony_ci	 * helper variables.
818c2ecf20Sopenharmony_ci	 */
828c2ecf20Sopenharmony_ci	volatile u16 *lo = &(regs->addr_lo);
838c2ecf20Sopenharmony_ci	volatile u16 *hi = &(regs->addr_hi);
848c2ecf20Sopenharmony_ci
858c2ecf20Sopenharmony_ci	mb();
868c2ecf20Sopenharmony_ci	*lo = bt431_set_value(ir & 0xff);
878c2ecf20Sopenharmony_ci	wmb();
888c2ecf20Sopenharmony_ci	*hi = bt431_set_value((ir >> 8) & 0xff);
898c2ecf20Sopenharmony_ci}
908c2ecf20Sopenharmony_ci
918c2ecf20Sopenharmony_ci/* Autoincrement read/write. */
928c2ecf20Sopenharmony_cistatic inline u8 bt431_read_reg_inc(struct bt431_regs *regs)
938c2ecf20Sopenharmony_ci{
948c2ecf20Sopenharmony_ci	/*
958c2ecf20Sopenharmony_ci	 * The compiler splits the write in two bytes without the
968c2ecf20Sopenharmony_ci	 * helper variable.
978c2ecf20Sopenharmony_ci	 */
988c2ecf20Sopenharmony_ci	volatile u16 *r = &(regs->addr_reg);
998c2ecf20Sopenharmony_ci
1008c2ecf20Sopenharmony_ci	mb();
1018c2ecf20Sopenharmony_ci	return bt431_get_value(*r);
1028c2ecf20Sopenharmony_ci}
1038c2ecf20Sopenharmony_ci
1048c2ecf20Sopenharmony_cistatic inline void bt431_write_reg_inc(struct bt431_regs *regs, u8 value)
1058c2ecf20Sopenharmony_ci{
1068c2ecf20Sopenharmony_ci	/*
1078c2ecf20Sopenharmony_ci	 * The compiler splits the write in two bytes without the
1088c2ecf20Sopenharmony_ci	 * helper variable.
1098c2ecf20Sopenharmony_ci	 */
1108c2ecf20Sopenharmony_ci	volatile u16 *r = &(regs->addr_reg);
1118c2ecf20Sopenharmony_ci
1128c2ecf20Sopenharmony_ci	mb();
1138c2ecf20Sopenharmony_ci	*r = bt431_set_value(value);
1148c2ecf20Sopenharmony_ci}
1158c2ecf20Sopenharmony_ci
1168c2ecf20Sopenharmony_cistatic inline u8 bt431_read_reg(struct bt431_regs *regs, int ir)
1178c2ecf20Sopenharmony_ci{
1188c2ecf20Sopenharmony_ci	bt431_select_reg(regs, ir);
1198c2ecf20Sopenharmony_ci	return bt431_read_reg_inc(regs);
1208c2ecf20Sopenharmony_ci}
1218c2ecf20Sopenharmony_ci
1228c2ecf20Sopenharmony_cistatic inline void bt431_write_reg(struct bt431_regs *regs, int ir, u8 value)
1238c2ecf20Sopenharmony_ci{
1248c2ecf20Sopenharmony_ci	bt431_select_reg(regs, ir);
1258c2ecf20Sopenharmony_ci	bt431_write_reg_inc(regs, value);
1268c2ecf20Sopenharmony_ci}
1278c2ecf20Sopenharmony_ci
1288c2ecf20Sopenharmony_ci/* Autoincremented read/write for the cursor map. */
1298c2ecf20Sopenharmony_cistatic inline u16 bt431_read_cmap_inc(struct bt431_regs *regs)
1308c2ecf20Sopenharmony_ci{
1318c2ecf20Sopenharmony_ci	/*
1328c2ecf20Sopenharmony_ci	 * The compiler splits the write in two bytes without the
1338c2ecf20Sopenharmony_ci	 * helper variable.
1348c2ecf20Sopenharmony_ci	 */
1358c2ecf20Sopenharmony_ci	volatile u16 *r = &(regs->addr_cmap);
1368c2ecf20Sopenharmony_ci
1378c2ecf20Sopenharmony_ci	mb();
1388c2ecf20Sopenharmony_ci	return *r;
1398c2ecf20Sopenharmony_ci}
1408c2ecf20Sopenharmony_ci
1418c2ecf20Sopenharmony_cistatic inline void bt431_write_cmap_inc(struct bt431_regs *regs, u16 value)
1428c2ecf20Sopenharmony_ci{
1438c2ecf20Sopenharmony_ci	/*
1448c2ecf20Sopenharmony_ci	 * The compiler splits the write in two bytes without the
1458c2ecf20Sopenharmony_ci	 * helper variable.
1468c2ecf20Sopenharmony_ci	 */
1478c2ecf20Sopenharmony_ci	volatile u16 *r = &(regs->addr_cmap);
1488c2ecf20Sopenharmony_ci
1498c2ecf20Sopenharmony_ci	mb();
1508c2ecf20Sopenharmony_ci	*r = value;
1518c2ecf20Sopenharmony_ci}
1528c2ecf20Sopenharmony_ci
1538c2ecf20Sopenharmony_cistatic inline u16 bt431_read_cmap(struct bt431_regs *regs, int cr)
1548c2ecf20Sopenharmony_ci{
1558c2ecf20Sopenharmony_ci	bt431_select_reg(regs, cr);
1568c2ecf20Sopenharmony_ci	return bt431_read_cmap_inc(regs);
1578c2ecf20Sopenharmony_ci}
1588c2ecf20Sopenharmony_ci
1598c2ecf20Sopenharmony_cistatic inline void bt431_write_cmap(struct bt431_regs *regs, int cr, u16 value)
1608c2ecf20Sopenharmony_ci{
1618c2ecf20Sopenharmony_ci	bt431_select_reg(regs, cr);
1628c2ecf20Sopenharmony_ci	bt431_write_cmap_inc(regs, value);
1638c2ecf20Sopenharmony_ci}
1648c2ecf20Sopenharmony_ci
1658c2ecf20Sopenharmony_cistatic inline void bt431_enable_cursor(struct bt431_regs *regs)
1668c2ecf20Sopenharmony_ci{
1678c2ecf20Sopenharmony_ci	bt431_write_reg(regs, BT431_REG_CMD,
1688c2ecf20Sopenharmony_ci			BT431_CMD_CURS_ENABLE | BT431_CMD_OR_CURSORS
1698c2ecf20Sopenharmony_ci			| BT431_CMD_4_1_MUX | BT431_CMD_THICK_1);
1708c2ecf20Sopenharmony_ci}
1718c2ecf20Sopenharmony_ci
1728c2ecf20Sopenharmony_cistatic inline void bt431_erase_cursor(struct bt431_regs *regs)
1738c2ecf20Sopenharmony_ci{
1748c2ecf20Sopenharmony_ci	bt431_write_reg(regs, BT431_REG_CMD, BT431_CMD_4_1_MUX);
1758c2ecf20Sopenharmony_ci}
1768c2ecf20Sopenharmony_ci
1778c2ecf20Sopenharmony_cistatic inline void bt431_position_cursor(struct bt431_regs *regs, u16 x, u16 y)
1788c2ecf20Sopenharmony_ci{
1798c2ecf20Sopenharmony_ci	/*
1808c2ecf20Sopenharmony_ci	 * Magic from the MACH sources.
1818c2ecf20Sopenharmony_ci	 *
1828c2ecf20Sopenharmony_ci	 * Cx = x + D + H - P
1838c2ecf20Sopenharmony_ci	 *  P = 37 if 1:1, 52 if 4:1, 57 if 5:1
1848c2ecf20Sopenharmony_ci	 *  D = pixel skew between outdata and external data
1858c2ecf20Sopenharmony_ci	 *  H = pixels between HSYNCH falling and active video
1868c2ecf20Sopenharmony_ci	 *
1878c2ecf20Sopenharmony_ci	 * Cy = y + V - 32
1888c2ecf20Sopenharmony_ci	 *  V = scanlines between HSYNCH falling, two or more
1898c2ecf20Sopenharmony_ci	 *      clocks after VSYNCH falling, and active video
1908c2ecf20Sopenharmony_ci	 */
1918c2ecf20Sopenharmony_ci	x += 412 - 52;
1928c2ecf20Sopenharmony_ci	y += 68 - 32;
1938c2ecf20Sopenharmony_ci
1948c2ecf20Sopenharmony_ci	/* Use autoincrement. */
1958c2ecf20Sopenharmony_ci	bt431_select_reg(regs, BT431_REG_CXLO);
1968c2ecf20Sopenharmony_ci	bt431_write_reg_inc(regs, x & 0xff); /* BT431_REG_CXLO */
1978c2ecf20Sopenharmony_ci	bt431_write_reg_inc(regs, (x >> 8) & 0x0f); /* BT431_REG_CXHI */
1988c2ecf20Sopenharmony_ci	bt431_write_reg_inc(regs, y & 0xff); /* BT431_REG_CYLO */
1998c2ecf20Sopenharmony_ci	bt431_write_reg_inc(regs, (y >> 8) & 0x0f); /* BT431_REG_CYHI */
2008c2ecf20Sopenharmony_ci}
2018c2ecf20Sopenharmony_ci
2028c2ecf20Sopenharmony_cistatic inline void bt431_set_cursor(struct bt431_regs *regs,
2038c2ecf20Sopenharmony_ci				    const char *data, const char *mask,
2048c2ecf20Sopenharmony_ci				    u16 rop, u16 width, u16 height)
2058c2ecf20Sopenharmony_ci{
2068c2ecf20Sopenharmony_ci	u16 x, y;
2078c2ecf20Sopenharmony_ci	int i;
2088c2ecf20Sopenharmony_ci
2098c2ecf20Sopenharmony_ci	i = 0;
2108c2ecf20Sopenharmony_ci	width = DIV_ROUND_UP(width, 8);
2118c2ecf20Sopenharmony_ci	bt431_select_reg(regs, BT431_REG_CRAM_BASE);
2128c2ecf20Sopenharmony_ci	for (y = 0; y < BT431_CURSOR_SIZE; y++)
2138c2ecf20Sopenharmony_ci		for (x = 0; x < BT431_CURSOR_SIZE / 8; x++) {
2148c2ecf20Sopenharmony_ci			u16 val = 0;
2158c2ecf20Sopenharmony_ci
2168c2ecf20Sopenharmony_ci			if (y < height && x < width) {
2178c2ecf20Sopenharmony_ci				val = mask[i];
2188c2ecf20Sopenharmony_ci				if (rop == ROP_XOR)
2198c2ecf20Sopenharmony_ci					val = (val << 8) | (val ^ data[i]);
2208c2ecf20Sopenharmony_ci				else
2218c2ecf20Sopenharmony_ci					val = (val << 8) | (val & data[i]);
2228c2ecf20Sopenharmony_ci				i++;
2238c2ecf20Sopenharmony_ci			}
2248c2ecf20Sopenharmony_ci			bt431_write_cmap_inc(regs, val);
2258c2ecf20Sopenharmony_ci		}
2268c2ecf20Sopenharmony_ci}
2278c2ecf20Sopenharmony_ci
2288c2ecf20Sopenharmony_cistatic inline void bt431_init_cursor(struct bt431_regs *regs)
2298c2ecf20Sopenharmony_ci{
2308c2ecf20Sopenharmony_ci	/* no crosshair window */
2318c2ecf20Sopenharmony_ci	bt431_select_reg(regs, BT431_REG_WXLO);
2328c2ecf20Sopenharmony_ci	bt431_write_reg_inc(regs, 0x00); /* BT431_REG_WXLO */
2338c2ecf20Sopenharmony_ci	bt431_write_reg_inc(regs, 0x00); /* BT431_REG_WXHI */
2348c2ecf20Sopenharmony_ci	bt431_write_reg_inc(regs, 0x00); /* BT431_REG_WYLO */
2358c2ecf20Sopenharmony_ci	bt431_write_reg_inc(regs, 0x00); /* BT431_REG_WYHI */
2368c2ecf20Sopenharmony_ci	bt431_write_reg_inc(regs, 0x00); /* BT431_REG_WWLO */
2378c2ecf20Sopenharmony_ci	bt431_write_reg_inc(regs, 0x00); /* BT431_REG_WWHI */
2388c2ecf20Sopenharmony_ci	bt431_write_reg_inc(regs, 0x00); /* BT431_REG_WHLO */
2398c2ecf20Sopenharmony_ci	bt431_write_reg_inc(regs, 0x00); /* BT431_REG_WHHI */
2408c2ecf20Sopenharmony_ci}
241