#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/string.h>
#include <linux/mm.h>
#include <linux/slab.h>
#include <linux/delay.h>
#include <linux/fb.h>
#include <linux/ioport.h>
#include <linux/init.h>
#include <linux/pci.h>
#include <linux/vmalloc.h>
#include <linux/pagemap.h>
#include <linux/console.h>
#include <linux/platform_device.h>
#include "sm750.h"
#include "sm750_accel.h"
static inline void write_dpr(struct lynx_accel *accel, int offset, u32 reg_value)
{
writel(reg_value, accel->dpr_base + offset);
}
static inline u32 read_dpr(struct lynx_accel *accel, int offset)
{
return readl(accel->dpr_base + offset);
}
static inline void write_dp_port(struct lynx_accel *accel, u32 data)
{
writel(data, accel->dp_port_base);
}
void sm750_hw_de_init(struct lynx_accel *accel)
{
u32 reg, clr;
write_dpr(accel, DE_MASKS, 0xFFFFFFFF);
reg = 0x3;
clr = DE_STRETCH_FORMAT_PATTERN_XY |
DE_STRETCH_FORMAT_PATTERN_Y_MASK |
DE_STRETCH_FORMAT_PATTERN_X_MASK |
DE_STRETCH_FORMAT_ADDRESSING_MASK |
DE_STRETCH_FORMAT_SOURCE_HEIGHT_MASK;
write_dpr(accel, DE_STRETCH_FORMAT,
(read_dpr(accel, DE_STRETCH_FORMAT) & ~clr) | reg);
write_dpr(accel, DE_CLIP_TL, 0);
write_dpr(accel, DE_CLIP_BR, 0);
write_dpr(accel, DE_COLOR_COMPARE_MASK, 0);
write_dpr(accel, DE_COLOR_COMPARE, 0);
clr = DE_CONTROL_TRANSPARENCY | DE_CONTROL_TRANSPARENCY_MATCH |
DE_CONTROL_TRANSPARENCY_SELECT;
write_dpr(accel, DE_CONTROL, read_dpr(accel, DE_CONTROL) & ~clr);
}
void sm750_hw_set2dformat(struct lynx_accel *accel, int fmt)
{
u32 reg;
reg = read_dpr(accel, DE_STRETCH_FORMAT);
reg &= ~DE_STRETCH_FORMAT_PIXEL_FORMAT_MASK;
reg |= ((fmt << DE_STRETCH_FORMAT_PIXEL_FORMAT_SHIFT) &
DE_STRETCH_FORMAT_PIXEL_FORMAT_MASK);
write_dpr(accel, DE_STRETCH_FORMAT, reg);
}
int sm750_hw_fillrect(struct lynx_accel *accel,
u32 base, u32 pitch, u32 Bpp,
u32 x, u32 y, u32 width, u32 height,
u32 color, u32 rop)
{
u32 de_ctrl;
if (accel->de_wait() != 0) {
pr_debug("De engine always busy\n");
return -1;
}
write_dpr(accel, DE_WINDOW_DESTINATION_BASE, base);
write_dpr(accel, DE_PITCH,
((pitch / Bpp << DE_PITCH_DESTINATION_SHIFT) &
DE_PITCH_DESTINATION_MASK) |
(pitch / Bpp & DE_PITCH_SOURCE_MASK));
write_dpr(accel, DE_WINDOW_WIDTH,
((pitch / Bpp << DE_WINDOW_WIDTH_DST_SHIFT) &
DE_WINDOW_WIDTH_DST_MASK) |
(pitch / Bpp & DE_WINDOW_WIDTH_SRC_MASK));
write_dpr(accel, DE_FOREGROUND, color);
write_dpr(accel, DE_DESTINATION,
((x << DE_DESTINATION_X_SHIFT) & DE_DESTINATION_X_MASK) |
(y & DE_DESTINATION_Y_MASK));
write_dpr(accel, DE_DIMENSION,
((width << DE_DIMENSION_X_SHIFT) & DE_DIMENSION_X_MASK) |
(height & DE_DIMENSION_Y_ET_MASK));
de_ctrl = DE_CONTROL_STATUS | DE_CONTROL_LAST_PIXEL |
DE_CONTROL_COMMAND_RECTANGLE_FILL | DE_CONTROL_ROP_SELECT |
(rop & DE_CONTROL_ROP_MASK);
write_dpr(accel, DE_CONTROL, de_ctrl);
return 0;
}
int sm750_hw_copyarea(struct lynx_accel *accel,
unsigned int source_base, unsigned int source_pitch,
unsigned int sx, unsigned int sy,
unsigned int dest_base, unsigned int dest_pitch,
unsigned int Bpp, unsigned int dx, unsigned int dy,
unsigned int width, unsigned int height,
unsigned int rop2)
{
unsigned int direction, de_ctrl;
direction = LEFT_TO_RIGHT;
de_ctrl = 0;
if (source_base == dest_base && source_pitch == dest_pitch) {
if (sy < dy) {
direction = BOTTOM_TO_TOP;
} else if (sy > dy) {
direction = TOP_TO_BOTTOM;
} else {
if (sx <= dx) {
direction = RIGHT_TO_LEFT;
} else {
direction = LEFT_TO_RIGHT;
}
}
}
if ((direction == BOTTOM_TO_TOP) || (direction == RIGHT_TO_LEFT)) {
sx += width - 1;
sy += height - 1;
dx += width - 1;
dy += height - 1;
}
write_dpr(accel, DE_WINDOW_SOURCE_BASE, source_base);
write_dpr(accel, DE_WINDOW_DESTINATION_BASE, dest_base);
write_dpr(accel, DE_PITCH,
((dest_pitch / Bpp << DE_PITCH_DESTINATION_SHIFT) &
DE_PITCH_DESTINATION_MASK) |
(source_pitch / Bpp & DE_PITCH_SOURCE_MASK));
write_dpr(accel, DE_WINDOW_WIDTH,
((dest_pitch / Bpp << DE_WINDOW_WIDTH_DST_SHIFT) &
DE_WINDOW_WIDTH_DST_MASK) |
(source_pitch / Bpp & DE_WINDOW_WIDTH_SRC_MASK));
if (accel->de_wait() != 0)
return -1;
write_dpr(accel, DE_SOURCE,
((sx << DE_SOURCE_X_K1_SHIFT) & DE_SOURCE_X_K1_MASK) |
(sy & DE_SOURCE_Y_K2_MASK));
write_dpr(accel, DE_DESTINATION,
((dx << DE_DESTINATION_X_SHIFT) & DE_DESTINATION_X_MASK) |
(dy & DE_DESTINATION_Y_MASK));
write_dpr(accel, DE_DIMENSION,
((width << DE_DIMENSION_X_SHIFT) & DE_DIMENSION_X_MASK) |
(height & DE_DIMENSION_Y_ET_MASK));
de_ctrl = (rop2 & DE_CONTROL_ROP_MASK) | DE_CONTROL_ROP_SELECT |
((direction == RIGHT_TO_LEFT) ? DE_CONTROL_DIRECTION : 0) |
DE_CONTROL_COMMAND_BITBLT | DE_CONTROL_STATUS;
write_dpr(accel, DE_CONTROL, de_ctrl);
return 0;
}
static unsigned int de_get_transparency(struct lynx_accel *accel)
{
unsigned int de_ctrl;
de_ctrl = read_dpr(accel, DE_CONTROL);
de_ctrl &= (DE_CONTROL_TRANSPARENCY_MATCH |
DE_CONTROL_TRANSPARENCY_SELECT | DE_CONTROL_TRANSPARENCY);
return de_ctrl;
}
int sm750_hw_imageblit(struct lynx_accel *accel, const char *src_buf,
u32 src_delta, u32 start_bit, u32 dest_base, u32 dest_pitch,
u32 byte_per_pixel, u32 dx, u32 dy, u32 width,
u32 height, u32 fg_color, u32 bg_color, u32 rop2)
{
unsigned int bytes_per_scan;
unsigned int words_per_scan;
unsigned int bytes_remain;
unsigned int de_ctrl = 0;
unsigned char remain[4];
int i, j;
start_bit &= 7;
bytes_per_scan = (width + start_bit + 7) / 8;
words_per_scan = bytes_per_scan & ~3;
bytes_remain = bytes_per_scan & 3;
if (accel->de_wait() != 0)
return -1;
write_dpr(accel, DE_WINDOW_SOURCE_BASE, 0);
write_dpr(accel, DE_WINDOW_DESTINATION_BASE, dest_base);
write_dpr(accel, DE_PITCH,
((dest_pitch / byte_per_pixel << DE_PITCH_DESTINATION_SHIFT) &
DE_PITCH_DESTINATION_MASK) |
(dest_pitch / byte_per_pixel & DE_PITCH_SOURCE_MASK));
write_dpr(accel, DE_WINDOW_WIDTH,
((dest_pitch / byte_per_pixel << DE_WINDOW_WIDTH_DST_SHIFT) &
DE_WINDOW_WIDTH_DST_MASK) |
(dest_pitch / byte_per_pixel & DE_WINDOW_WIDTH_SRC_MASK));
write_dpr(accel, DE_SOURCE,
(start_bit << DE_SOURCE_X_K1_SHIFT) &
DE_SOURCE_X_K1_MONO_MASK);
write_dpr(accel, DE_DESTINATION,
((dx << DE_DESTINATION_X_SHIFT) & DE_DESTINATION_X_MASK) |
(dy & DE_DESTINATION_Y_MASK));
write_dpr(accel, DE_DIMENSION,
((width << DE_DIMENSION_X_SHIFT) & DE_DIMENSION_X_MASK) |
(height & DE_DIMENSION_Y_ET_MASK));
write_dpr(accel, DE_FOREGROUND, fg_color);
write_dpr(accel, DE_BACKGROUND, bg_color);
de_ctrl = (rop2 & DE_CONTROL_ROP_MASK) |
DE_CONTROL_ROP_SELECT | DE_CONTROL_COMMAND_HOST_WRITE |
DE_CONTROL_HOST | DE_CONTROL_STATUS;
write_dpr(accel, DE_CONTROL, de_ctrl | de_get_transparency(accel));
for (i = 0; i < height; i++) {
for (j = 0; j < (words_per_scan / 4); j++)
write_dp_port(accel, *(unsigned int *)(src_buf + (j * 4)));
if (bytes_remain) {
memcpy(remain, src_buf + words_per_scan,
bytes_remain);
write_dp_port(accel, *(unsigned int *)remain);
}
src_buf += src_delta;
}
return 0;
}