📄 dispc.c
字号:
/* * OMAP2 display controller support * * Copyright (C) 2005 Nokia Corporation * Author: Imre Deak <imre.deak@nokia.com> * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */#include <linux/kernel.h>#include <linux/dma-mapping.h>#include <linux/mm.h>#include <linux/vmalloc.h>#include <linux/clk.h>#include <linux/io.h>#include <mach/sram.h>#include <mach/omapfb.h>#include <mach/board.h>#include "dispc.h"#define MODULE_NAME "dispc"#define DSS_BASE 0x48050000#define DSS_SYSCONFIG 0x0010#define DISPC_BASE 0x48050400/* DISPC common */#define DISPC_REVISION 0x0000#define DISPC_SYSCONFIG 0x0010#define DISPC_SYSSTATUS 0x0014#define DISPC_IRQSTATUS 0x0018#define DISPC_IRQENABLE 0x001C#define DISPC_CONTROL 0x0040#define DISPC_CONFIG 0x0044#define DISPC_CAPABLE 0x0048#define DISPC_DEFAULT_COLOR0 0x004C#define DISPC_DEFAULT_COLOR1 0x0050#define DISPC_TRANS_COLOR0 0x0054#define DISPC_TRANS_COLOR1 0x0058#define DISPC_LINE_STATUS 0x005C#define DISPC_LINE_NUMBER 0x0060#define DISPC_TIMING_H 0x0064#define DISPC_TIMING_V 0x0068#define DISPC_POL_FREQ 0x006C#define DISPC_DIVISOR 0x0070#define DISPC_SIZE_DIG 0x0078#define DISPC_SIZE_LCD 0x007C#define DISPC_DATA_CYCLE1 0x01D4#define DISPC_DATA_CYCLE2 0x01D8#define DISPC_DATA_CYCLE3 0x01DC/* DISPC GFX plane */#define DISPC_GFX_BA0 0x0080#define DISPC_GFX_BA1 0x0084#define DISPC_GFX_POSITION 0x0088#define DISPC_GFX_SIZE 0x008C#define DISPC_GFX_ATTRIBUTES 0x00A0#define DISPC_GFX_FIFO_THRESHOLD 0x00A4#define DISPC_GFX_FIFO_SIZE_STATUS 0x00A8#define DISPC_GFX_ROW_INC 0x00AC#define DISPC_GFX_PIXEL_INC 0x00B0#define DISPC_GFX_WINDOW_SKIP 0x00B4#define DISPC_GFX_TABLE_BA 0x00B8/* DISPC Video plane 1/2 */#define DISPC_VID1_BASE 0x00BC#define DISPC_VID2_BASE 0x014C/* Offsets into DISPC_VID1/2_BASE */#define DISPC_VID_BA0 0x0000#define DISPC_VID_BA1 0x0004#define DISPC_VID_POSITION 0x0008#define DISPC_VID_SIZE 0x000C#define DISPC_VID_ATTRIBUTES 0x0010#define DISPC_VID_FIFO_THRESHOLD 0x0014#define DISPC_VID_FIFO_SIZE_STATUS 0x0018#define DISPC_VID_ROW_INC 0x001C#define DISPC_VID_PIXEL_INC 0x0020#define DISPC_VID_FIR 0x0024#define DISPC_VID_PICTURE_SIZE 0x0028#define DISPC_VID_ACCU0 0x002C#define DISPC_VID_ACCU1 0x0030/* 8 elements in 8 byte increments */#define DISPC_VID_FIR_COEF_H0 0x0034/* 8 elements in 8 byte increments */#define DISPC_VID_FIR_COEF_HV0 0x0038/* 5 elements in 4 byte increments */#define DISPC_VID_CONV_COEF0 0x0074#define DISPC_IRQ_FRAMEMASK 0x0001#define DISPC_IRQ_VSYNC 0x0002#define DISPC_IRQ_EVSYNC_EVEN 0x0004#define DISPC_IRQ_EVSYNC_ODD 0x0008#define DISPC_IRQ_ACBIAS_COUNT_STAT 0x0010#define DISPC_IRQ_PROG_LINE_NUM 0x0020#define DISPC_IRQ_GFX_FIFO_UNDERFLOW 0x0040#define DISPC_IRQ_GFX_END_WIN 0x0080#define DISPC_IRQ_PAL_GAMMA_MASK 0x0100#define DISPC_IRQ_OCP_ERR 0x0200#define DISPC_IRQ_VID1_FIFO_UNDERFLOW 0x0400#define DISPC_IRQ_VID1_END_WIN 0x0800#define DISPC_IRQ_VID2_FIFO_UNDERFLOW 0x1000#define DISPC_IRQ_VID2_END_WIN 0x2000#define DISPC_IRQ_SYNC_LOST 0x4000#define DISPC_IRQ_MASK_ALL 0x7fff#define DISPC_IRQ_MASK_ERROR (DISPC_IRQ_GFX_FIFO_UNDERFLOW | \ DISPC_IRQ_VID1_FIFO_UNDERFLOW | \ DISPC_IRQ_VID2_FIFO_UNDERFLOW | \ DISPC_IRQ_SYNC_LOST)#define RFBI_CONTROL 0x48050040#define MAX_PALETTE_SIZE (256 * 16)#define FLD_MASK(pos, len) (((1 << len) - 1) << pos)#define MOD_REG_FLD(reg, mask, val) \ dispc_write_reg((reg), (dispc_read_reg(reg) & ~(mask)) | (val));#define OMAP2_SRAM_START 0x40200000/* Maximum size, in reality this is smaller if SRAM is partially locked. */#define OMAP2_SRAM_SIZE 0xa0000 /* 640k *//* We support the SDRAM / SRAM types. See OMAPFB_PLANE_MEMTYPE_* in omapfb.h */#define DISPC_MEMTYPE_NUM 2#define RESMAP_SIZE(_page_cnt) \ ((_page_cnt + (sizeof(unsigned long) * 8) - 1) / 8)#define RESMAP_PTR(_res_map, _page_nr) \ (((_res_map)->map) + (_page_nr) / (sizeof(unsigned long) * 8))#define RESMAP_MASK(_page_nr) \ (1 << ((_page_nr) & (sizeof(unsigned long) * 8 - 1)))struct resmap { unsigned long start; unsigned page_cnt; unsigned long *map;};static struct { void __iomem *base; struct omapfb_mem_desc mem_desc; struct resmap *res_map[DISPC_MEMTYPE_NUM]; atomic_t map_count[OMAPFB_PLANE_NUM]; dma_addr_t palette_paddr; void *palette_vaddr; int ext_mode; unsigned long enabled_irqs; void (*irq_callback)(void *); void *irq_callback_data; struct completion frame_done; int fir_hinc[OMAPFB_PLANE_NUM]; int fir_vinc[OMAPFB_PLANE_NUM]; struct clk *dss_ick, *dss1_fck; struct clk *dss_54m_fck; enum omapfb_update_mode update_mode; struct omapfb_device *fbdev; struct omapfb_color_key color_key;} dispc;static void enable_lcd_clocks(int enable);static void inline dispc_write_reg(int idx, u32 val){ __raw_writel(val, dispc.base + idx);}static u32 inline dispc_read_reg(int idx){ u32 l = __raw_readl(dispc.base + idx); return l;}/* Select RFBI or bypass mode */static void enable_rfbi_mode(int enable){ u32 l; l = dispc_read_reg(DISPC_CONTROL); /* Enable RFBI, GPIO0/1 */ l &= ~((1 << 11) | (1 << 15) | (1 << 16)); l |= enable ? (1 << 11) : 0; /* RFBI En: GPIO0/1=10 RFBI Dis: GPIO0/1=11 */ l |= 1 << 15; l |= enable ? 0 : (1 << 16); dispc_write_reg(DISPC_CONTROL, l); /* Set bypass mode in RFBI module */ l = __raw_readl(IO_ADDRESS(RFBI_CONTROL)); l |= enable ? 0 : (1 << 1); __raw_writel(l, IO_ADDRESS(RFBI_CONTROL));}static void set_lcd_data_lines(int data_lines){ u32 l; int code = 0; switch (data_lines) { case 12: code = 0; break; case 16: code = 1; break; case 18: code = 2; break; case 24: code = 3; break; default: BUG(); } l = dispc_read_reg(DISPC_CONTROL); l &= ~(0x03 << 8); l |= code << 8; dispc_write_reg(DISPC_CONTROL, l);}static void set_load_mode(int mode){ BUG_ON(mode & ~(DISPC_LOAD_CLUT_ONLY | DISPC_LOAD_FRAME_ONLY | DISPC_LOAD_CLUT_ONCE_FRAME)); MOD_REG_FLD(DISPC_CONFIG, 0x03 << 1, mode << 1);}void omap_dispc_set_lcd_size(int x, int y){ BUG_ON((x > (1 << 11)) || (y > (1 << 11))); enable_lcd_clocks(1); MOD_REG_FLD(DISPC_SIZE_LCD, FLD_MASK(16, 11) | FLD_MASK(0, 11), ((y - 1) << 16) | (x - 1)); enable_lcd_clocks(0);}EXPORT_SYMBOL(omap_dispc_set_lcd_size);void omap_dispc_set_digit_size(int x, int y){ BUG_ON((x > (1 << 11)) || (y > (1 << 11))); enable_lcd_clocks(1); MOD_REG_FLD(DISPC_SIZE_DIG, FLD_MASK(16, 11) | FLD_MASK(0, 11), ((y - 1) << 16) | (x - 1)); enable_lcd_clocks(0);}EXPORT_SYMBOL(omap_dispc_set_digit_size);static void setup_plane_fifo(int plane, int ext_mode){ const u32 ftrs_reg[] = { DISPC_GFX_FIFO_THRESHOLD, DISPC_VID1_BASE + DISPC_VID_FIFO_THRESHOLD, DISPC_VID2_BASE + DISPC_VID_FIFO_THRESHOLD }; const u32 fsz_reg[] = { DISPC_GFX_FIFO_SIZE_STATUS, DISPC_VID1_BASE + DISPC_VID_FIFO_SIZE_STATUS, DISPC_VID2_BASE + DISPC_VID_FIFO_SIZE_STATUS }; int low, high; u32 l; BUG_ON(plane > 2); l = dispc_read_reg(fsz_reg[plane]); l &= FLD_MASK(0, 9); if (ext_mode) { low = l * 3 / 4; high = l; } else { low = l / 4; high = l * 3 / 4; } MOD_REG_FLD(ftrs_reg[plane], FLD_MASK(16, 9) | FLD_MASK(0, 9), (high << 16) | low);}void omap_dispc_enable_lcd_out(int enable){ enable_lcd_clocks(1); MOD_REG_FLD(DISPC_CONTROL, 1, enable ? 1 : 0); enable_lcd_clocks(0);}EXPORT_SYMBOL(omap_dispc_enable_lcd_out);void omap_dispc_enable_digit_out(int enable){ enable_lcd_clocks(1); MOD_REG_FLD(DISPC_CONTROL, 1 << 1, enable ? 1 << 1 : 0); enable_lcd_clocks(0);}EXPORT_SYMBOL(omap_dispc_enable_digit_out);static inline int _setup_plane(int plane, int channel_out, u32 paddr, int screen_width, int pos_x, int pos_y, int width, int height, int color_mode){ const u32 at_reg[] = { DISPC_GFX_ATTRIBUTES, DISPC_VID1_BASE + DISPC_VID_ATTRIBUTES, DISPC_VID2_BASE + DISPC_VID_ATTRIBUTES }; const u32 ba_reg[] = { DISPC_GFX_BA0, DISPC_VID1_BASE + DISPC_VID_BA0, DISPC_VID2_BASE + DISPC_VID_BA0 }; const u32 ps_reg[] = { DISPC_GFX_POSITION, DISPC_VID1_BASE + DISPC_VID_POSITION, DISPC_VID2_BASE + DISPC_VID_POSITION }; const u32 sz_reg[] = { DISPC_GFX_SIZE, DISPC_VID1_BASE + DISPC_VID_PICTURE_SIZE, DISPC_VID2_BASE + DISPC_VID_PICTURE_SIZE }; const u32 ri_reg[] = { DISPC_GFX_ROW_INC, DISPC_VID1_BASE + DISPC_VID_ROW_INC, DISPC_VID2_BASE + DISPC_VID_ROW_INC }; const u32 vs_reg[] = { 0, DISPC_VID1_BASE + DISPC_VID_SIZE, DISPC_VID2_BASE + DISPC_VID_SIZE }; int chout_shift, burst_shift; int chout_val; int color_code; int bpp; int cconv_en; int set_vsize; u32 l;#ifdef VERBOSE dev_dbg(dispc.fbdev->dev, "plane %d channel %d paddr %#08x scr_width %d" " pos_x %d pos_y %d width %d height %d color_mode %d\n", plane, channel_out, paddr, screen_width, pos_x, pos_y, width, height, color_mode);#endif set_vsize = 0; switch (plane) { case OMAPFB_PLANE_GFX: burst_shift = 6; chout_shift = 8; break; case OMAPFB_PLANE_VID1: case OMAPFB_PLANE_VID2: burst_shift = 14; chout_shift = 16; set_vsize = 1; break; default: return -EINVAL; } switch (channel_out) { case OMAPFB_CHANNEL_OUT_LCD: chout_val = 0; break; case OMAPFB_CHANNEL_OUT_DIGIT: chout_val = 1; break; default: return -EINVAL; } cconv_en = 0; switch (color_mode) { case OMAPFB_COLOR_RGB565: color_code = DISPC_RGB_16_BPP; bpp = 16; break; case OMAPFB_COLOR_YUV422: if (plane == 0) return -EINVAL; color_code = DISPC_UYVY_422; cconv_en = 1; bpp = 16; break; case OMAPFB_COLOR_YUY422: if (plane == 0) return -EINVAL; color_code = DISPC_YUV2_422; cconv_en = 1; bpp = 16; break; default: return -EINVAL; } l = dispc_read_reg(at_reg[plane]); l &= ~(0x0f << 1); l |= color_code << 1; l &= ~(1 << 9); l |= cconv_en << 9; l &= ~(0x03 << burst_shift); l |= DISPC_BURST_8x32 << burst_shift; l &= ~(1 << chout_shift); l |= chout_val << chout_shift; dispc_write_reg(at_reg[plane], l); dispc_write_reg(ba_reg[plane], paddr); MOD_REG_FLD(ps_reg[plane], FLD_MASK(16, 11) | FLD_MASK(0, 11), (pos_y << 16) | pos_x); MOD_REG_FLD(sz_reg[plane], FLD_MASK(16, 11) | FLD_MASK(0, 11), ((height - 1) << 16) | (width - 1)); if (set_vsize) { /* Set video size if set_scale hasn't set it */ if (!dispc.fir_vinc[plane]) MOD_REG_FLD(vs_reg[plane], FLD_MASK(16, 11), (height - 1) << 16); if (!dispc.fir_hinc[plane]) MOD_REG_FLD(vs_reg[plane], FLD_MASK(0, 11), width - 1); } dispc_write_reg(ri_reg[plane], (screen_width - width) * bpp / 8 + 1); return height * screen_width * bpp / 8;}static int omap_dispc_setup_plane(int plane, int channel_out, unsigned long offset, int screen_width, int pos_x, int pos_y, int width, int height, int color_mode){ u32 paddr; int r; if ((unsigned)plane > dispc.mem_desc.region_cnt) return -EINVAL; paddr = dispc.mem_desc.region[plane].paddr + offset; enable_lcd_clocks(1); r = _setup_plane(plane, channel_out, paddr, screen_width, pos_x, pos_y, width, height, color_mode); enable_lcd_clocks(0); return r;}static void write_firh_reg(int plane, int reg, u32 value){ u32 base; if (plane == 1) base = DISPC_VID1_BASE + DISPC_VID_FIR_COEF_H0; else base = DISPC_VID2_BASE + DISPC_VID_FIR_COEF_H0; dispc_write_reg(base + reg * 8, value);}static void write_firhv_reg(int plane, int reg, u32 value){ u32 base; if (plane == 1) base = DISPC_VID1_BASE + DISPC_VID_FIR_COEF_HV0; else base = DISPC_VID2_BASE + DISPC_VID_FIR_COEF_HV0; dispc_write_reg(base + reg * 8, value);}static void set_upsampling_coef_table(int plane){ const u32 coef[][2] = { { 0x00800000, 0x00800000 }, { 0x0D7CF800, 0x037B02FF }, { 0x1E70F5FF, 0x0C6F05FE }, { 0x335FF5FE, 0x205907FB }, { 0xF74949F7, 0x00404000 }, { 0xF55F33FB, 0x075920FE }, { 0xF5701EFE, 0x056F0CFF }, { 0xF87C0DFF, 0x027B0300 }, }; int i; for (i = 0; i < 8; i++) { write_firh_reg(plane, i, coef[i][0]); write_firhv_reg(plane, i, coef[i][1]); }}static int omap_dispc_set_scale(int plane,
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -