📄 sdum.c
字号:
/* * drivers/video/pnx4008/sdum.c * * Display Update Master support * * Authors: Grigory Tolstolytkin <gtolstolytkin@ru.mvista.com> * Vitaly Wool <vitalywool@gmail.com> * Based on Philips Semiconductors's code * * Copyrght (c) 2005-2006 MontaVista Software, Inc. * Copyright (c) 2005 Philips Semiconductors * This file is licensed under the terms of the GNU General Public License * version 2. This program is licensed "as is" without any warranty of any * kind, whether express or implied. */#include <linux/module.h>#include <linux/kernel.h>#include <linux/errno.h>#include <linux/string.h>#include <linux/mm.h>#include <linux/tty.h>#include <linux/slab.h>#include <linux/vmalloc.h>#include <linux/delay.h>#include <linux/interrupt.h>#include <linux/platform_device.h>#include <linux/fb.h>#include <linux/init.h>#include <linux/dma-mapping.h>#include <linux/clk.h>#include <asm/uaccess.h>#include <mach/gpio.h>#include "sdum.h"#include "fbcommon.h"#include "dum.h"/* Framebuffers we have */static struct pnx4008_fb_addr { int fb_type; long addr_offset; long fb_length;} fb_addr[] = { [0] = { FB_TYPE_YUV, 0, 0xB0000 }, [1] = { FB_TYPE_RGB, 0xB0000, 0x50000 },};static struct dum_data { u32 lcd_phys_start; u32 lcd_virt_start; u32 slave_phys_base; u32 *slave_virt_base; int fb_owning_channel[MAX_DUM_CHANNELS]; struct dumchannel_uf chan_uf_store[MAX_DUM_CHANNELS];} dum_data;/* Different local helper functions */static u32 nof_pixels_dx(struct dum_ch_setup *ch_setup){ return (ch_setup->xmax - ch_setup->xmin + 1);}static u32 nof_pixels_dy(struct dum_ch_setup *ch_setup){ return (ch_setup->ymax - ch_setup->ymin + 1);}static u32 nof_pixels_dxy(struct dum_ch_setup *ch_setup){ return (nof_pixels_dx(ch_setup) * nof_pixels_dy(ch_setup));}static u32 nof_bytes(struct dum_ch_setup *ch_setup){ u32 r = nof_pixels_dxy(ch_setup); switch (ch_setup->format) { case RGB888: case RGB666: r *= 4; break; default: r *= 2; break; } return r;}static u32 build_command(int disp_no, u32 reg, u32 val){ return ((disp_no << 26) | BIT(25) | (val << 16) | (disp_no << 10) | (reg << 0));}static u32 build_double_index(int disp_no, u32 val){ return ((disp_no << 26) | (val << 16) | (disp_no << 10) | (val << 0));}static void build_disp_window(struct dum_ch_setup * ch_setup, struct disp_window * dw){ dw->ymin = ch_setup->ymin; dw->ymax = ch_setup->ymax; dw->xmin_l = ch_setup->xmin & 0xFF; dw->xmin_h = (ch_setup->xmin & BIT(8)) >> 8; dw->xmax_l = ch_setup->xmax & 0xFF; dw->xmax_h = (ch_setup->xmax & BIT(8)) >> 8;}static int put_channel(struct dumchannel chan){ int i = chan.channelnr; if (i < 0 || i > MAX_DUM_CHANNELS) return -EINVAL; else { DUM_CH_MIN(i) = chan.dum_ch_min; DUM_CH_MAX(i) = chan.dum_ch_max; DUM_CH_CONF(i) = chan.dum_ch_conf; DUM_CH_CTRL(i) = chan.dum_ch_ctrl; } return 0;}static void clear_channel(int channr){ struct dumchannel chan; chan.channelnr = channr; chan.dum_ch_min = 0; chan.dum_ch_max = 0; chan.dum_ch_conf = 0; chan.dum_ch_ctrl = 0; put_channel(chan);}static int put_cmd_string(struct cmdstring cmds){ u16 *cmd_str_virtaddr; u32 *cmd_ptr0_virtaddr; u32 cmd_str_physaddr; int i = cmds.channelnr; if (i < 0 || i > MAX_DUM_CHANNELS) return -EINVAL; else if ((cmd_ptr0_virtaddr = (int *)ioremap_nocache(DUM_COM_BASE, sizeof(int) * MAX_DUM_CHANNELS)) == NULL) return -EIOREMAPFAILED; else { cmd_str_physaddr = ioread32(&cmd_ptr0_virtaddr[cmds.channelnr]); if ((cmd_str_virtaddr = (u16 *) ioremap_nocache(cmd_str_physaddr, sizeof(cmds))) == NULL) { iounmap(cmd_ptr0_virtaddr); return -EIOREMAPFAILED; } else { int t; for (t = 0; t < 8; t++) iowrite16(*((u16 *)&cmds.prestringlen + t), cmd_str_virtaddr + t); for (t = 0; t < cmds.prestringlen / 2; t++) iowrite16(*((u16 *)&cmds.precmd + t), cmd_str_virtaddr + t + 8); for (t = 0; t < cmds.poststringlen / 2; t++) iowrite16(*((u16 *)&cmds.postcmd + t), cmd_str_virtaddr + t + 8 + cmds.prestringlen / 2); iounmap(cmd_ptr0_virtaddr); iounmap(cmd_str_virtaddr); } } return 0;}static u32 dum_ch_setup(int ch_no, struct dum_ch_setup * ch_setup){ struct cmdstring cmds_c; struct cmdstring *cmds = &cmds_c; struct disp_window dw; int standard; u32 orientation = 0; struct dumchannel chan = { 0 }; int ret; if ((ch_setup->xmirror) || (ch_setup->ymirror) || (ch_setup->rotate)) { standard = 0; orientation = BIT(1); /* always set 9-bit-bus */ if (ch_setup->xmirror) orientation |= BIT(4); if (ch_setup->ymirror) orientation |= BIT(3); if (ch_setup->rotate) orientation |= BIT(0); } else standard = 1; cmds->channelnr = ch_no; /* build command string header */ if (standard) { cmds->prestringlen = 32; cmds->poststringlen = 0; } else { cmds->prestringlen = 48; cmds->poststringlen = 16; } cmds->format = (u16) ((ch_setup->disp_no << 4) | (BIT(3)) | (ch_setup->format)); cmds->reserved = 0x0; cmds->startaddr_low = (ch_setup->minadr & 0xFFFF); cmds->startaddr_high = (ch_setup->minadr >> 16); if ((ch_setup->minadr == 0) && (ch_setup->maxadr == 0) && (ch_setup->xmin == 0) && (ch_setup->ymin == 0) && (ch_setup->xmax == 0) && (ch_setup->ymax == 0)) { cmds->pixdatlen_low = 0; cmds->pixdatlen_high = 0; } else { u32 nbytes = nof_bytes(ch_setup); cmds->pixdatlen_low = (nbytes & 0xFFFF); cmds->pixdatlen_high = (nbytes >> 16); } if (ch_setup->slave_trans) cmds->pixdatlen_high |= BIT(15); /* build pre-string */ build_disp_window(ch_setup, &dw); if (standard) { cmds->precmd[0] = build_command(ch_setup->disp_no, DISP_XMIN_L_REG, 0x99); cmds->precmd[1] = build_command(ch_setup->disp_no, DISP_XMIN_L_REG, dw.xmin_l); cmds->precmd[2] = build_command(ch_setup->disp_no, DISP_XMIN_H_REG, dw.xmin_h); cmds->precmd[3] = build_command(ch_setup->disp_no, DISP_YMIN_REG, dw.ymin); cmds->precmd[4] = build_command(ch_setup->disp_no, DISP_XMAX_L_REG, dw.xmax_l); cmds->precmd[5] = build_command(ch_setup->disp_no, DISP_XMAX_H_REG, dw.xmax_h); cmds->precmd[6] = build_command(ch_setup->disp_no, DISP_YMAX_REG, dw.ymax); cmds->precmd[7] = build_double_index(ch_setup->disp_no, DISP_PIXEL_REG); } else { if (dw.xmin_l == ch_no) cmds->precmd[0] = build_command(ch_setup->disp_no, DISP_XMIN_L_REG, 0x99); else cmds->precmd[0] = build_command(ch_setup->disp_no, DISP_XMIN_L_REG, ch_no); cmds->precmd[1] = build_command(ch_setup->disp_no, DISP_XMIN_L_REG, dw.xmin_l); cmds->precmd[2] = build_command(ch_setup->disp_no, DISP_XMIN_H_REG, dw.xmin_h); cmds->precmd[3] = build_command(ch_setup->disp_no, DISP_YMIN_REG, dw.ymin); cmds->precmd[4] = build_command(ch_setup->disp_no, DISP_XMAX_L_REG, dw.xmax_l); cmds->precmd[5] = build_command(ch_setup->disp_no, DISP_XMAX_H_REG, dw.xmax_h); cmds->precmd[6] = build_command(ch_setup->disp_no, DISP_YMAX_REG, dw.ymax); cmds->precmd[7] = build_command(ch_setup->disp_no, DISP_1_REG, orientation); cmds->precmd[8] = build_double_index(ch_setup->disp_no, DISP_PIXEL_REG); cmds->precmd[9] = build_double_index(ch_setup->disp_no, DISP_PIXEL_REG); cmds->precmd[0xA] = build_double_index(ch_setup->disp_no, DISP_PIXEL_REG); cmds->precmd[0xB] = build_double_index(ch_setup->disp_no, DISP_PIXEL_REG); cmds->postcmd[0] = build_command(ch_setup->disp_no, DISP_1_REG, BIT(1)); cmds->postcmd[1] = build_command(ch_setup->disp_no, DISP_DUMMY1_REG, 1); cmds->postcmd[2] = build_command(ch_setup->disp_no, DISP_DUMMY1_REG, 2); cmds->postcmd[3] = build_command(ch_setup->disp_no, DISP_DUMMY1_REG, 3); } if ((ret = put_cmd_string(cmds_c)) != 0) { return ret; } chan.channelnr = cmds->channelnr; chan.dum_ch_min = ch_setup->dirtybuffer + ch_setup->minadr; chan.dum_ch_max = ch_setup->dirtybuffer + ch_setup->maxadr; chan.dum_ch_conf = 0x002; chan.dum_ch_ctrl = 0x04; put_channel(chan); return 0;}static u32 display_open(int ch_no, int auto_update, u32 * dirty_buffer, u32 * frame_buffer, u32 xpos, u32 ypos, u32 w, u32 h){ struct dum_ch_setup k; int ret; /* keep width & height within display area */ if ((xpos + w) > DISP_MAX_X_SIZE) w = DISP_MAX_X_SIZE - xpos; if ((ypos + h) > DISP_MAX_Y_SIZE) h = DISP_MAX_Y_SIZE - ypos; /* assume 1 display only */ k.disp_no = 0; k.xmin = xpos; k.ymin = ypos; k.xmax = xpos + (w - 1); k.ymax = ypos + (h - 1); /* adjust min and max values if necessary */ if (k.xmin > DISP_MAX_X_SIZE - 1) k.xmin = DISP_MAX_X_SIZE - 1; if (k.ymin > DISP_MAX_Y_SIZE - 1) k.ymin = DISP_MAX_Y_SIZE - 1; if (k.xmax > DISP_MAX_X_SIZE - 1) k.xmax = DISP_MAX_X_SIZE - 1; if (k.ymax > DISP_MAX_Y_SIZE - 1) k.ymax = DISP_MAX_Y_SIZE - 1; k.xmirror = 0; k.ymirror = 0; k.rotate = 0; k.minadr = (u32) frame_buffer; k.maxadr = (u32) frame_buffer + (((w - 1) << 10) | ((h << 2) - 2)); k.pad = PAD_1024; k.dirtybuffer = (u32) dirty_buffer; k.format = RGB888; k.hwdirty = 0; k.slave_trans = 0; ret = dum_ch_setup(ch_no, &k); return ret;}static void lcd_reset(void){ u32 *dum_pio_base = (u32 *)IO_ADDRESS(PNX4008_PIO_BASE); udelay(1); iowrite32(BIT(19), &dum_pio_base[2]); udelay(1); iowrite32(BIT(19), &dum_pio_base[1]); udelay(1);}static int dum_init(struct platform_device *pdev){ struct clk *clk; /* enable DUM clock */ clk = clk_get(&pdev->dev, "dum_ck"); if (IS_ERR(clk)) { printk(KERN_ERR "pnx4008_dum: Unable to access DUM clock\n"); return PTR_ERR(clk); } clk_set_rate(clk, 1); clk_put(clk); DUM_CTRL = V_DUM_RESET; /* set priority to "round-robin". All other params to "false" */ DUM_CONF = BIT(9); /* Display 1 */ DUM_WTCFG1 = PNX4008_DUM_WT_CFG; DUM_RTCFG1 = PNX4008_DUM_RT_CFG; DUM_TCFG = PNX4008_DUM_T_CFG; return 0;}static void dum_chan_init(void){ int i = 0, ch = 0; u32 *cmdptrs; u32 *cmdstrings; DUM_COM_BASE = CMDSTRING_BASEADDR + BYTES_PER_CMDSTRING * NR_OF_CMDSTRINGS; if ((cmdptrs = (u32 *) ioremap_nocache(DUM_COM_BASE, sizeof(u32) * NR_OF_CMDSTRINGS)) == NULL) return; for (ch = 0; ch < NR_OF_CMDSTRINGS; ch++) iowrite32(CMDSTRING_BASEADDR + BYTES_PER_CMDSTRING * ch, cmdptrs + ch); for (ch = 0; ch < MAX_DUM_CHANNELS; ch++) clear_channel(ch);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -