#include "harddoomdev.h" #include "harddoom.h" #include "doomcode.h" #include "pci.h" #include "private_data.h" #include "util.h" #define PING_FREQUENCY 0x80 void doomdev_write(void __iomem *iomem, size_t addr, uint32_t data) { iowrite32(data, iomem + addr); } uint32_t doomdev_read(void __iomem *iomem, size_t addr) { return ioread32(iomem + addr); } void write_command(void __iomem *iomem, uint32_t command) { doomdev_write(iomem, HARDDOOM_FIFO_SEND, command); } void enable_intr(void __iomem *iomem, uint32_t intr) { uint32_t interrupts; interrupts = doomdev_read(iomem, HARDDOOM_INTR_ENABLE); doomdev_write(iomem, HARDDOOM_INTR_ENABLE, interrupts | intr); } void disable_intr(void __iomem *iomem, uint32_t intr) { uint32_t interrupts; interrupts = doomdev_read(iomem, HARDDOOM_INTR_ENABLE); doomdev_write(iomem, HARDDOOM_INTR_ENABLE, interrupts & (~intr)); } void send_command(struct doom_data *doom_data, uint32_t command) { uint32_t free; free = doomdev_read(doom_data->iomem, HARDDOOM_FIFO_FREE); if (free == 0) { deactivate_intr(doom_data->iomem, HARDDOOM_INTR_PONG_ASYNC); free = doomdev_read(doom_data->iomem, HARDDOOM_FIFO_FREE); } if (free == 0) { enable_intr(doom_data->iomem, HARDDOOM_INTR_PONG_ASYNC); down(&doom_data->pong_async_sem); } if (doom_data->cmd_counter > PING_FREQUENCY) { doom_data->cmd_counter = 0; write_command(doom_data->iomem, HARDDOOM_CMD_PING_ASYNC); } else { doom_data->cmd_counter++; } write_command(doom_data->iomem, command); } uint32_t get_interrupts(void __iomem *iomem) { return doomdev_read(iomem, HARDDOOM_INTR); } uint32_t get_enabled_interrupts(void __iomem *iomem) { return doomdev_read(iomem, HARDDOOM_INTR_ENABLE); } void deactivate_intr(void __iomem *iomem, uint32_t intr) { doomdev_write(iomem, HARDDOOM_INTR, intr); } void ping_sync(struct doom_data *doom_data) { send_command(doom_data, HARDDOOM_CMD_PING_SYNC); } void set_surf_src_pt(struct doom_data *doom_data, dma_addr_t page_table) { if (doom_data->surf_src_pt != page_table) { doom_data->surf_src_pt = page_table; send_command(doom_data, HARDDOOM_CMD_SURF_SRC_PT(page_table)); } } void set_surf_dst_pt(struct doom_data *doom_data, dma_addr_t page_table) { if (doom_data->surf_dst_pt != page_table) { doom_data->surf_dst_pt = page_table; send_command(doom_data, HARDDOOM_CMD_SURF_DST_PT(page_table)); } } void set_surf_dims(struct doom_data *doom_data, uint32_t width, uint32_t height) { if (doom_data->surf_dims_w != width || doom_data->surf_dims_h != height) { doom_data->surf_dims_w = width; doom_data->surf_dims_h = height; send_command(doom_data, HARDDOOM_CMD_SURF_DIMS(width, height)); } } void set_xy_a(struct doom_data *doom_data, uint16_t x, uint16_t y) { send_command(doom_data, HARDDOOM_CMD_XY_A(x, y)); } void set_xy_b(struct doom_data *doom_data, uint16_t x, uint16_t y) { send_command(doom_data, HARDDOOM_CMD_XY_B(x, y)); } void set_fill_color(struct doom_data *doom_data, uint8_t color) { send_command(doom_data, HARDDOOM_CMD_FILL_COLOR(color)); } void set_texture_pt(struct doom_data *doom_data, dma_addr_t page_table_dev) { if (doom_data->texture_pt != page_table_dev) { doom_data->texture_pt = page_table_dev; send_command(doom_data, HARDDOOM_CMD_TEXTURE_PT(page_table_dev)); } } void set_texture_dims(struct doom_data *doom_data, uint32_t size, uint16_t height) { if (doom_data->texture_dims_s != size || doom_data->texture_dims_h != height) { doom_data->texture_dims_s = size; doom_data->texture_dims_h = height; send_command(doom_data, HARDDOOM_CMD_TEXTURE_DIMS(size,height)); } } void set_flat(struct doom_data *doom_data, dma_addr_t flat_dev) { if (doom_data->flat_addr != flat_dev) { doom_data->flat_addr = flat_dev; send_command(doom_data, HARDDOOM_CMD_FLAT_ADDR(flat_dev)); } } void set_colormap(struct doom_data *doom_data, dma_addr_t colors_dev) { if (doom_data->colors_addr != colors_dev) { doom_data->colors_addr = colors_dev; send_command(doom_data, HARDDOOM_CMD_COLORMAP_ADDR(colors_dev)); } } void set_trans(struct doom_data *doom_data, dma_addr_t colors_dev) { if (doom_data->trans_addr != colors_dev) { doom_data->trans_addr = colors_dev; send_command(doom_data, HARDDOOM_CMD_TRANSLATION_ADDR(colors_dev)); } } void set_ustart(struct doom_data *doom_data, uint32_t ustart) { send_command(doom_data, HARDDOOM_CMD_USTART(ustart)); } void set_ustep(struct doom_data *doom_data, uint32_t ustep) { send_command(doom_data, HARDDOOM_CMD_USTEP(ustep)); } void set_vstart(struct doom_data *doom_data, uint32_t vstart) { send_command(doom_data, HARDDOOM_CMD_VSTART(vstart)); } void set_vstep(struct doom_data *doom_data, uint32_t vstep) { send_command(doom_data, HARDDOOM_CMD_VSTEP(vstep)); } void set_draw_params(struct doom_data *doom_data, uint8_t flags) { if (doom_data->draw_params != flags) { doom_data->draw_params = flags; send_command(doom_data, HARDDOOM_CMD_DRAW_PARAMS(flags)); } } void fill_rect(struct surface_data *surface_data, struct doomdev_fill_rect rect) { set_surf_dst_pt(surface_data->doom_data, surface_data->page_table_dev); set_surf_dims(surface_data->doom_data, surface_data->width, surface_data->height); set_xy_a(surface_data->doom_data, rect.pos_dst_x, rect.pos_dst_y); set_fill_color(surface_data->doom_data, rect.color); send_command(surface_data->doom_data, HARDDOOM_CMD_FILL_RECT(rect.width, rect.height)); } void draw_line(struct surface_data *surface_data, struct doomdev_line line) { set_surf_dst_pt(surface_data->doom_data, surface_data->page_table_dev); set_surf_dims(surface_data->doom_data, surface_data->width, surface_data->height); set_xy_a(surface_data->doom_data, line.pos_a_x, line.pos_a_y); set_xy_b(surface_data->doom_data, line.pos_b_x, line.pos_b_y); set_fill_color(surface_data->doom_data, line.color); send_command(surface_data->doom_data, HARDDOOM_CMD_DRAW_LINE); } void copy_rect(struct surface_data *dst_data, struct surface_data *src_data, struct doomdev_copy_rect rect) { set_surf_dst_pt(dst_data->doom_data, dst_data->page_table_dev); set_surf_src_pt(dst_data->doom_data, src_data->page_table_dev); set_surf_dims(dst_data->doom_data, dst_data->width, dst_data->height); set_xy_a(dst_data->doom_data, rect.pos_dst_x, rect.pos_dst_y); set_xy_b(dst_data->doom_data, rect.pos_src_x, rect.pos_src_y); send_command(dst_data->doom_data, HARDDOOM_CMD_COPY_RECT(rect.width, rect.height)); } void draw_column(struct surface_data *surface_data, struct texture_data *texture_data, struct doomdev_column column, struct colors_data *colors_data, struct colors_data *trans_data, uint8_t flags, uint8_t trans_idx) { uint16_t y1, y2; y1 = min(column.y1, column.y2); y2 = max(column.y1, column.y2); set_surf_dst_pt(surface_data->doom_data, surface_data->page_table_dev); set_surf_dims(surface_data->doom_data, surface_data->width, surface_data->height); set_draw_params(surface_data->doom_data, flags); set_xy_a(surface_data->doom_data, column.x, y1); set_xy_b(surface_data->doom_data, column.x, y2); if (!(flags & HARDDOOM_DRAW_PARAMS_FUZZ)) { set_texture_pt(surface_data->doom_data, texture_data->page_table_dev); set_texture_dims(surface_data->doom_data, texture_data->size, texture_data->height); set_ustart(surface_data->doom_data, column.ustart); set_ustep(surface_data->doom_data, column.ustep); } if (flags & HARDDOOM_DRAW_PARAMS_FUZZ || flags & HARDDOOM_DRAW_PARAMS_COLORMAP) { set_colormap(surface_data->doom_data, colors_data->colors_dev + HARDDOOM_COLORMAP_SIZE * column.colormap_idx); } if (flags & HARDDOOM_DRAW_PARAMS_TRANSLATE) { set_trans(surface_data->doom_data, trans_data->colors_dev + HARDDOOM_COLORMAP_SIZE * trans_idx); } send_command(surface_data->doom_data, HARDDOOM_CMD_DRAW_COLUMN(column.texture_offset)); } void draw_span(struct surface_data *surface_data, struct flat_data *flat_data, struct doomdev_span span) { uint16_t x1, x2; x1 = min(span.x1, span.x2); x2 = max(span.x1, span.x2); set_surf_dst_pt(surface_data->doom_data, surface_data->page_table_dev); set_surf_dims(surface_data->doom_data, surface_data->width, surface_data->height); set_flat(surface_data->doom_data, flat_data->flat_dev); set_xy_a(surface_data->doom_data, x1, span.y); set_xy_b(surface_data->doom_data, x2, span.y); set_ustart(surface_data->doom_data, span.ustart); set_ustep(surface_data->doom_data, span.ustep); set_vstart(surface_data->doom_data, span.vstart); set_vstep(surface_data->doom_data, span.vstep); set_draw_params(surface_data->doom_data, 0); send_command(surface_data->doom_data, HARDDOOM_CMD_DRAW_SPAN); } void draw_background(struct surface_data *surface_data, struct flat_data *flat_data) { set_surf_dst_pt(surface_data->doom_data, surface_data->page_table_dev); set_flat(surface_data->doom_data, flat_data->flat_dev); send_command(surface_data->doom_data, HARDDOOM_CMD_DRAW_BACKGROUND); } uint32_t doomdev_read_stat(void __iomem *iomem, size_t stat) { return doomdev_read(iomem, HARDDOOM_STATS(stat)); } void load_microcode(void __iomem *iomem) { int i; doomdev_write(iomem, HARDDOOM_FE_CODE_ADDR, 0); for (i = 0; i < ARRAY_SIZE(doomcode); i++) { doomdev_write(iomem, HARDDOOM_FE_CODE_WINDOW, doomcode[i]); } } void start_dev(struct pci_dev *dev) { struct doom_data *data; void __iomem *iomem; data = pci_get_drvdata(dev); iomem = data->iomem; load_microcode(iomem); doomdev_write(iomem, HARDDOOM_RESET, 0xffffffe); doomdev_write(iomem, HARDDOOM_INTR, HARDDOOM_INTR_MASK ^ HARDDOOM_INTR_PONG_ASYNC); doomdev_write(iomem, HARDDOOM_INTR_ENABLE, HARDDOOM_INTR_MASK); doomdev_write(iomem, HARDDOOM_ENABLE, HARDDOOM_ENABLE_ALL ^ HARDDOOM_ENABLE_FETCH_CMD); set_surf_dst_pt(data, 0); set_surf_src_pt(data, 0); set_texture_pt(data, 0); set_flat(data, 0); set_colormap(data, 0); set_surf_dims(data, 0, 0); set_texture_dims(data, 0, 0); set_draw_params(data, 0); } void shutdown_dev(struct pci_dev *dev) { struct doom_data *data; void __iomem *iomem; data = pci_get_drvdata(dev); iomem = data->iomem; doomdev_write(iomem, HARDDOOM_ENABLE, 0); doomdev_write(iomem, HARDDOOM_INTR_ENABLE, 0); doomdev_read(iomem, 0); }