1 // SPDX-License-Identifier: GPL-2.0 2 #include <linux/module.h> 3 #include <linux/kernel.h> 4 #include <linux/errno.h> 5 #include <linux/string.h> 6 #include <linux/mm.h> 7 #include <linux/slab.h> 8 #include <linux/delay.h> 9 #include <linux/fb.h> 10 #include <linux/ioport.h> 11 #include <linux/init.h> 12 #include <linux/pci.h> 13 #include <linux/vmalloc.h> 14 #include <linux/pagemap.h> 15 #include <linux/console.h> 16 #include <linux/platform_device.h> 17 #include <linux/screen_info.h> 18 19 #include "sm750.h" 20 #include "sm750_cursor.h" 21 22 #define poke32(addr, data) \ 23 writel((data), cursor->mmio + (addr)) 24 25 /* cursor control for voyager and 718/750*/ 26 #define HWC_ADDRESS 0x0 27 #define HWC_ADDRESS_ENABLE BIT(31) 28 #define HWC_ADDRESS_EXT BIT(27) 29 #define HWC_ADDRESS_CS BIT(26) 30 #define HWC_ADDRESS_ADDRESS_MASK 0x3ffffff 31 32 #define HWC_LOCATION 0x4 33 #define HWC_LOCATION_TOP BIT(27) 34 #define HWC_LOCATION_Y_SHIFT 16 35 #define HWC_LOCATION_Y_MASK (0x7ff << 16) 36 #define HWC_LOCATION_LEFT BIT(11) 37 #define HWC_LOCATION_X_MASK 0x7ff 38 39 #define HWC_COLOR_12 0x8 40 #define HWC_COLOR_12_2_RGB565_SHIFT 16 41 #define HWC_COLOR_12_2_RGB565_MASK (0xffff << 16) 42 #define HWC_COLOR_12_1_RGB565_MASK 0xffff 43 44 #define HWC_COLOR_3 0xC 45 #define HWC_COLOR_3_RGB565_MASK 0xffff 46 47 /* hw_cursor_xxx works for voyager,718 and 750 */ 48 void sm750_hw_cursor_enable(struct lynx_cursor *cursor) 49 { 50 u32 reg; 51 52 reg = (cursor->offset & HWC_ADDRESS_ADDRESS_MASK) | HWC_ADDRESS_ENABLE; 53 poke32(HWC_ADDRESS, reg); 54 } 55 56 void sm750_hw_cursor_disable(struct lynx_cursor *cursor) 57 { 58 poke32(HWC_ADDRESS, 0); 59 } 60 61 void sm750_hw_cursor_setSize(struct lynx_cursor *cursor, int w, int h) 62 { 63 cursor->w = w; 64 cursor->h = h; 65 } 66 67 void sm750_hw_cursor_setPos(struct lynx_cursor *cursor, int x, int y) 68 { 69 u32 reg; 70 71 reg = ((y << HWC_LOCATION_Y_SHIFT) & HWC_LOCATION_Y_MASK) | 72 (x & HWC_LOCATION_X_MASK); 73 poke32(HWC_LOCATION, reg); 74 } 75 76 void sm750_hw_cursor_setColor(struct lynx_cursor *cursor, u32 fg, u32 bg) 77 { 78 u32 reg = (fg << HWC_COLOR_12_2_RGB565_SHIFT) & 79 HWC_COLOR_12_2_RGB565_MASK; 80 81 poke32(HWC_COLOR_12, reg | (bg & HWC_COLOR_12_1_RGB565_MASK)); 82 poke32(HWC_COLOR_3, 0xffe0); 83 } 84 85 void sm750_hw_cursor_setData(struct lynx_cursor *cursor, u16 rop, 86 const u8 *pcol, const u8 *pmsk) 87 { 88 int i, j, count, pitch, offset; 89 u8 color, mask, opr; 90 u16 data; 91 void __iomem *pbuffer, *pstart; 92 93 /* in byte*/ 94 pitch = cursor->w >> 3; 95 96 /* in byte */ 97 count = pitch * cursor->h; 98 99 /* in byte */ 100 offset = cursor->max_w * 2 / 8; 101 102 data = 0; 103 pstart = cursor->vstart; 104 pbuffer = pstart; 105 106 for (i = 0; i < count; i++) { 107 color = *pcol++; 108 mask = *pmsk++; 109 data = 0; 110 111 for (j = 0; j < 8; j++) { 112 if (mask & (0x80 >> j)) { 113 if (rop == ROP_XOR) 114 opr = mask ^ color; 115 else 116 opr = mask & color; 117 118 /* 2 stands for forecolor and 1 for backcolor */ 119 data |= ((opr & (0x80 >> j)) ? 2 : 1) << (j * 2); 120 } 121 } 122 iowrite16(data, pbuffer); 123 124 /* assume pitch is 1,2,4,8,...*/ 125 if ((i + 1) % pitch == 0) { 126 /* need a return */ 127 pstart += offset; 128 pbuffer = pstart; 129 } else { 130 pbuffer += sizeof(u16); 131 } 132 } 133 } 134 135 void sm750_hw_cursor_setData2(struct lynx_cursor *cursor, u16 rop, 136 const u8 *pcol, const u8 *pmsk) 137 { 138 int i, j, count, pitch, offset; 139 u8 color, mask; 140 u16 data; 141 void __iomem *pbuffer, *pstart; 142 143 /* in byte*/ 144 pitch = cursor->w >> 3; 145 146 /* in byte */ 147 count = pitch * cursor->h; 148 149 /* in byte */ 150 offset = cursor->max_w * 2 / 8; 151 152 data = 0; 153 pstart = cursor->vstart; 154 pbuffer = pstart; 155 156 for (i = 0; i < count; i++) { 157 color = *pcol++; 158 mask = *pmsk++; 159 data = 0; 160 161 for (j = 0; j < 8; j++) { 162 if (mask & (1 << j)) 163 data |= ((color & (1 << j)) ? 1 : 2) << (j * 2); 164 } 165 iowrite16(data, pbuffer); 166 167 /* assume pitch is 1,2,4,8,...*/ 168 if (!(i & (pitch - 1))) { 169 /* need a return */ 170 pstart += offset; 171 pbuffer = pstart; 172 } else { 173 pbuffer += sizeof(u16); 174 } 175 } 176 } 177