0001
0002
0003
0004
0005
0006
0007
0008
0009
0010 #include <asm/unaligned.h>
0011
0012 #include "udl_drv.h"
0013
0014 #define MAX_CMD_PIXELS 255
0015
0016 #define RLX_HEADER_BYTES 7
0017 #define MIN_RLX_PIX_BYTES 4
0018 #define MIN_RLX_CMD_BYTES (RLX_HEADER_BYTES + MIN_RLX_PIX_BYTES)
0019
0020 #define RLE_HEADER_BYTES 6
0021 #define MIN_RLE_PIX_BYTES 3
0022 #define MIN_RLE_CMD_BYTES (RLE_HEADER_BYTES + MIN_RLE_PIX_BYTES)
0023
0024 #define RAW_HEADER_BYTES 6
0025 #define MIN_RAW_PIX_BYTES 2
0026 #define MIN_RAW_CMD_BYTES (RAW_HEADER_BYTES + MIN_RAW_PIX_BYTES)
0027
0028
0029
0030
0031
0032
0033
0034
0035 #if 0
0036 static int udl_trim_hline(const u8 *bback, const u8 **bfront, int *width_bytes)
0037 {
0038 int j, k;
0039 const unsigned long *back = (const unsigned long *) bback;
0040 const unsigned long *front = (const unsigned long *) *bfront;
0041 const int width = *width_bytes / sizeof(unsigned long);
0042 int identical = width;
0043 int start = width;
0044 int end = width;
0045
0046 for (j = 0; j < width; j++) {
0047 if (back[j] != front[j]) {
0048 start = j;
0049 break;
0050 }
0051 }
0052
0053 for (k = width - 1; k > j; k--) {
0054 if (back[k] != front[k]) {
0055 end = k+1;
0056 break;
0057 }
0058 }
0059
0060 identical = start + (width - end);
0061 *bfront = (u8 *) &front[start];
0062 *width_bytes = (end - start) * sizeof(unsigned long);
0063
0064 return identical * sizeof(unsigned long);
0065 }
0066 #endif
0067
0068 static inline u16 pixel32_to_be16(const uint32_t pixel)
0069 {
0070 return (((pixel >> 3) & 0x001f) |
0071 ((pixel >> 5) & 0x07e0) |
0072 ((pixel >> 8) & 0xf800));
0073 }
0074
0075 static inline u16 get_pixel_val16(const uint8_t *pixel, int log_bpp)
0076 {
0077 u16 pixel_val16;
0078 if (log_bpp == 1)
0079 pixel_val16 = *(const uint16_t *)pixel;
0080 else
0081 pixel_val16 = pixel32_to_be16(*(const uint32_t *)pixel);
0082 return pixel_val16;
0083 }
0084
0085
0086
0087
0088
0089
0090
0091
0092
0093
0094
0095
0096
0097
0098
0099
0100
0101
0102
0103
0104
0105
0106
0107
0108
0109
0110
0111
0112 static void udl_compress_hline16(
0113 const u8 **pixel_start_ptr,
0114 const u8 *const pixel_end,
0115 uint32_t *device_address_ptr,
0116 uint8_t **command_buffer_ptr,
0117 const uint8_t *const cmd_buffer_end, int log_bpp)
0118 {
0119 const int bpp = 1 << log_bpp;
0120 const u8 *pixel = *pixel_start_ptr;
0121 uint32_t dev_addr = *device_address_ptr;
0122 uint8_t *cmd = *command_buffer_ptr;
0123
0124 while ((pixel_end > pixel) &&
0125 (cmd_buffer_end - MIN_RLX_CMD_BYTES > cmd)) {
0126 uint8_t *raw_pixels_count_byte = NULL;
0127 uint8_t *cmd_pixels_count_byte = NULL;
0128 const u8 *raw_pixel_start = NULL;
0129 const u8 *cmd_pixel_start, *cmd_pixel_end = NULL;
0130 uint16_t pixel_val16;
0131
0132 *cmd++ = 0xaf;
0133 *cmd++ = 0x6b;
0134 *cmd++ = (uint8_t) ((dev_addr >> 16) & 0xFF);
0135 *cmd++ = (uint8_t) ((dev_addr >> 8) & 0xFF);
0136 *cmd++ = (uint8_t) ((dev_addr) & 0xFF);
0137
0138 cmd_pixels_count_byte = cmd++;
0139 cmd_pixel_start = pixel;
0140
0141 raw_pixels_count_byte = cmd++;
0142 raw_pixel_start = pixel;
0143
0144 cmd_pixel_end = pixel + (min3(MAX_CMD_PIXELS + 1UL,
0145 (unsigned long)(pixel_end - pixel) >> log_bpp,
0146 (unsigned long)(cmd_buffer_end - 1 - cmd) / 2) << log_bpp);
0147
0148 pixel_val16 = get_pixel_val16(pixel, log_bpp);
0149
0150 while (pixel < cmd_pixel_end) {
0151 const u8 *const start = pixel;
0152 const uint16_t repeating_pixel_val16 = pixel_val16;
0153
0154 put_unaligned_be16(pixel_val16, cmd);
0155
0156 cmd += 2;
0157 pixel += bpp;
0158
0159 while (pixel < cmd_pixel_end) {
0160 pixel_val16 = get_pixel_val16(pixel, log_bpp);
0161 if (pixel_val16 != repeating_pixel_val16)
0162 break;
0163 pixel += bpp;
0164 }
0165
0166 if (unlikely(pixel > start + bpp)) {
0167
0168 *raw_pixels_count_byte = (((start -
0169 raw_pixel_start) >> log_bpp) + 1) & 0xFF;
0170
0171
0172 *cmd++ = (((pixel - start) >> log_bpp) - 1) & 0xFF;
0173
0174
0175 raw_pixel_start = pixel;
0176 raw_pixels_count_byte = cmd++;
0177 }
0178 }
0179
0180 if (pixel > raw_pixel_start) {
0181
0182 *raw_pixels_count_byte = ((pixel - raw_pixel_start) >> log_bpp) & 0xFF;
0183 } else {
0184
0185 cmd--;
0186 }
0187
0188 *cmd_pixels_count_byte = ((pixel - cmd_pixel_start) >> log_bpp) & 0xFF;
0189 dev_addr += ((pixel - cmd_pixel_start) >> log_bpp) * 2;
0190 }
0191
0192 if (cmd_buffer_end <= MIN_RLX_CMD_BYTES + cmd) {
0193
0194 if (cmd_buffer_end > cmd)
0195 memset(cmd, 0xAF, cmd_buffer_end - cmd);
0196 cmd = (uint8_t *) cmd_buffer_end;
0197 }
0198
0199 *command_buffer_ptr = cmd;
0200 *pixel_start_ptr = pixel;
0201 *device_address_ptr = dev_addr;
0202
0203 return;
0204 }
0205
0206
0207
0208
0209
0210
0211
0212 int udl_render_hline(struct drm_device *dev, int log_bpp, struct urb **urb_ptr,
0213 const char *front, char **urb_buf_ptr,
0214 u32 byte_offset, u32 device_byte_offset,
0215 u32 byte_width)
0216 {
0217 const u8 *line_start, *line_end, *next_pixel;
0218 u32 base16 = 0 + (device_byte_offset >> log_bpp) * 2;
0219 struct urb *urb = *urb_ptr;
0220 u8 *cmd = *urb_buf_ptr;
0221 u8 *cmd_end = (u8 *) urb->transfer_buffer + urb->transfer_buffer_length;
0222
0223 BUG_ON(!(log_bpp == 1 || log_bpp == 2));
0224
0225 line_start = (u8 *) (front + byte_offset);
0226 next_pixel = line_start;
0227 line_end = next_pixel + byte_width;
0228
0229 while (next_pixel < line_end) {
0230
0231 udl_compress_hline16(&next_pixel,
0232 line_end, &base16,
0233 (u8 **) &cmd, (u8 *) cmd_end, log_bpp);
0234
0235 if (cmd >= cmd_end) {
0236 int len = cmd - (u8 *) urb->transfer_buffer;
0237 int ret = udl_submit_urb(dev, urb, len);
0238 if (ret)
0239 return ret;
0240 urb = udl_get_urb(dev);
0241 if (!urb)
0242 return -EAGAIN;
0243 *urb_ptr = urb;
0244 cmd = urb->transfer_buffer;
0245 cmd_end = &cmd[urb->transfer_buffer_length];
0246 }
0247 }
0248
0249 *urb_buf_ptr = cmd;
0250
0251 return 0;
0252 }