mirror of
https://github.com/Ysurac/openmptcprouter.git
synced 2025-03-09 15:40:20 +00:00
Kernel 5.4 RUTX support
This commit is contained in:
parent
839fcf1cab
commit
cfce9f52b2
7376 changed files with 3902 additions and 546 deletions
68
common/package/boot/uboot-ipq40xx/src/drivers/video/Makefile
Normal file
68
common/package/boot/uboot-ipq40xx/src/drivers/video/Makefile
Normal file
|
|
@ -0,0 +1,68 @@
|
|||
#
|
||||
# (C) Copyright 2000-2007
|
||||
# Wolfgang Denk, DENX Software Engineering, wd@denx.de.
|
||||
#
|
||||
# See file CREDITS for list of people who contributed to this
|
||||
# project.
|
||||
#
|
||||
# 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 $(TOPDIR)/config.mk
|
||||
|
||||
LIB := $(obj)libvideo.o
|
||||
|
||||
COBJS-$(CONFIG_ATI_RADEON_FB) += ati_radeon_fb.o videomodes.o
|
||||
COBJS-$(CONFIG_ATMEL_HLCD) += atmel_hlcdfb.o
|
||||
COBJS-$(CONFIG_ATMEL_LCD) += atmel_lcdfb.o
|
||||
COBJS-$(CONFIG_CFB_CONSOLE) += cfb_console.o
|
||||
COBJS-$(CONFIG_EXYNOS_FB) += exynos_fb.o exynos_fimd.o
|
||||
COBJS-$(CONFIG_EXYNOS_MIPI_DSIM) += exynos_mipi_dsi.o exynos_mipi_dsi_common.o \
|
||||
exynos_mipi_dsi_lowlevel.o
|
||||
COBJS-$(CONFIG_FSL_DIU_FB) += fsl_diu_fb.o videomodes.o
|
||||
COBJS-$(CONFIG_S6E8AX0) += s6e8ax0.o
|
||||
COBJS-$(CONFIG_S6E63D6) += s6e63d6.o
|
||||
COBJS-$(CONFIG_SED156X) += sed156x.o
|
||||
COBJS-$(CONFIG_VIDEO_AMBA) += amba.o
|
||||
COBJS-$(CONFIG_VIDEO_CT69000) += ct69000.o videomodes.o
|
||||
COBJS-$(CONFIG_VIDEO_DA8XX) += da8xx-fb.o videomodes.o
|
||||
COBJS-$(CONFIG_VIDEO_MB862xx) += mb862xx.o videomodes.o
|
||||
COBJS-$(CONFIG_VIDEO_MB86R0xGDC) += mb86r0xgdc.o videomodes.o
|
||||
COBJS-$(CONFIG_VIDEO_MX3) += mx3fb.o videomodes.o
|
||||
COBJS-$(CONFIG_VIDEO_IPUV3) += mxc_ipuv3_fb.o ipu_common.o ipu_disp.o
|
||||
COBJS-$(CONFIG_VIDEO_OMAP3) += omap3_dss.o
|
||||
COBJS-$(CONFIG_VIDEO_SED13806) += sed13806.o
|
||||
COBJS-$(CONFIG_VIDEO_SM501) += sm501.o
|
||||
COBJS-$(CONFIG_VIDEO_SMI_LYNXEM) += smiLynxEM.o videomodes.o
|
||||
COBJS-$(CONFIG_VIDEO_VCXK) += bus_vcxk.o
|
||||
|
||||
COBJS := $(sort $(COBJS-y))
|
||||
SRCS := $(COBJS:.o=.c)
|
||||
OBJS := $(addprefix $(obj),$(COBJS))
|
||||
|
||||
all: $(LIB)
|
||||
|
||||
$(LIB): $(obj).depend $(OBJS)
|
||||
$(call cmd_link_o_target, $(OBJS))
|
||||
|
||||
#########################################################################
|
||||
|
||||
# defines $(obj).depend target
|
||||
include $(SRCTREE)/rules.mk
|
||||
|
||||
sinclude $(obj).depend
|
||||
|
||||
#########################################################################
|
||||
79
common/package/boot/uboot-ipq40xx/src/drivers/video/amba.c
Normal file
79
common/package/boot/uboot-ipq40xx/src/drivers/video/amba.c
Normal file
|
|
@ -0,0 +1,79 @@
|
|||
/*
|
||||
* Driver for AMBA PrimeCell CLCD
|
||||
*
|
||||
* Copyright (C) 2009 Alessandro Rubini
|
||||
*
|
||||
* See file CREDITS for list of people who contributed to this
|
||||
* project.
|
||||
*
|
||||
* 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 <common.h>
|
||||
#include <asm/io.h>
|
||||
#include <lcd.h>
|
||||
#include <amba_clcd.h>
|
||||
|
||||
/* These variables are required by lcd.c -- although it sets them by itself */
|
||||
int lcd_line_length;
|
||||
int lcd_color_fg;
|
||||
int lcd_color_bg;
|
||||
void *lcd_base;
|
||||
void *lcd_console_address;
|
||||
short console_col;
|
||||
short console_row;
|
||||
|
||||
/*
|
||||
* To use this driver you need to provide the following in board files:
|
||||
* a panel_info definition
|
||||
* an lcd_enable function (can't define a weak default with current code)
|
||||
*/
|
||||
|
||||
/* There is nothing to do with color registers, we use true color */
|
||||
void lcd_setcolreg(ushort regno, ushort red, ushort green, ushort blue)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
/* Low level initialization of the logic cell: depends on panel_info */
|
||||
void lcd_ctrl_init(void *lcdbase)
|
||||
{
|
||||
struct clcd_config *config;
|
||||
struct clcd_registers *regs;
|
||||
u32 cntl;
|
||||
|
||||
config = panel_info.priv;
|
||||
regs = config->address;
|
||||
cntl = config->cntl & ~CNTL_LCDEN;
|
||||
|
||||
/* Lazily, just copy the registers over: first control with disable */
|
||||
writel(cntl, ®s->cntl);
|
||||
|
||||
writel(config->tim0, ®s->tim0);
|
||||
writel(config->tim1, ®s->tim1);
|
||||
writel(config->tim2, ®s->tim2);
|
||||
writel(config->tim3, ®s->tim3);
|
||||
writel((u32)lcdbase, ®s->ubas);
|
||||
/* finally, enable */
|
||||
writel(cntl | CNTL_LCDEN, ®s->cntl);
|
||||
}
|
||||
|
||||
/* This is trivial, and copied from atmel_lcdfb.c */
|
||||
ulong calc_fbsize(void)
|
||||
{
|
||||
return ((panel_info.vl_col * panel_info.vl_row *
|
||||
NBITS(panel_info.vl_bpix)) / 8) + PAGE_SIZE;
|
||||
}
|
||||
211
common/package/boot/uboot-ipq40xx/src/drivers/video/ati_ids.h
Normal file
211
common/package/boot/uboot-ipq40xx/src/drivers/video/ati_ids.h
Normal file
|
|
@ -0,0 +1,211 @@
|
|||
/*
|
||||
* ATI PCI IDs from XFree86, kept here to make sync'ing with
|
||||
* XFree much simpler. Currently, this list is only used by
|
||||
* radeonfb
|
||||
*/
|
||||
|
||||
#define PCI_CHIP_RV380_3150 0x3150
|
||||
#define PCI_CHIP_RV380_3151 0x3151
|
||||
#define PCI_CHIP_RV380_3152 0x3152
|
||||
#define PCI_CHIP_RV380_3153 0x3153
|
||||
#define PCI_CHIP_RV380_3154 0x3154
|
||||
#define PCI_CHIP_RV380_3156 0x3156
|
||||
#define PCI_CHIP_RV380_3E50 0x3E50
|
||||
#define PCI_CHIP_RV380_3E51 0x3E51
|
||||
#define PCI_CHIP_RV380_3E52 0x3E52
|
||||
#define PCI_CHIP_RV380_3E53 0x3E53
|
||||
#define PCI_CHIP_RV380_3E54 0x3E54
|
||||
#define PCI_CHIP_RV380_3E56 0x3E56
|
||||
#define PCI_CHIP_RS100_4136 0x4136
|
||||
#define PCI_CHIP_RS200_4137 0x4137
|
||||
#define PCI_CHIP_R300_AD 0x4144
|
||||
#define PCI_CHIP_R300_AE 0x4145
|
||||
#define PCI_CHIP_R300_AF 0x4146
|
||||
#define PCI_CHIP_R300_AG 0x4147
|
||||
#define PCI_CHIP_R350_AH 0x4148
|
||||
#define PCI_CHIP_R350_AI 0x4149
|
||||
#define PCI_CHIP_R350_AJ 0x414A
|
||||
#define PCI_CHIP_R350_AK 0x414B
|
||||
#define PCI_CHIP_RV350_AP 0x4150
|
||||
#define PCI_CHIP_RV350_AQ 0x4151
|
||||
#define PCI_CHIP_RV360_AR 0x4152
|
||||
#define PCI_CHIP_RV350_AS 0x4153
|
||||
#define PCI_CHIP_RV350_AT 0x4154
|
||||
#define PCI_CHIP_RV350_AV 0x4156
|
||||
#define PCI_CHIP_MACH32 0x4158
|
||||
#define PCI_CHIP_RS250_4237 0x4237
|
||||
#define PCI_CHIP_R200_BB 0x4242
|
||||
#define PCI_CHIP_R200_BC 0x4243
|
||||
#define PCI_CHIP_RS100_4336 0x4336
|
||||
#define PCI_CHIP_RS200_4337 0x4337
|
||||
#define PCI_CHIP_MACH64CT 0x4354
|
||||
#define PCI_CHIP_MACH64CX 0x4358
|
||||
#define PCI_CHIP_RS250_4437 0x4437
|
||||
#define PCI_CHIP_MACH64ET 0x4554
|
||||
#define PCI_CHIP_MACH64GB 0x4742
|
||||
#define PCI_CHIP_MACH64GD 0x4744
|
||||
#define PCI_CHIP_MACH64GI 0x4749
|
||||
#define PCI_CHIP_MACH64GL 0x474C
|
||||
#define PCI_CHIP_MACH64GM 0x474D
|
||||
#define PCI_CHIP_MACH64GN 0x474E
|
||||
#define PCI_CHIP_MACH64GO 0x474F
|
||||
#define PCI_CHIP_MACH64GP 0x4750
|
||||
#define PCI_CHIP_MACH64GQ 0x4751
|
||||
#define PCI_CHIP_MACH64GR 0x4752
|
||||
#define PCI_CHIP_MACH64GS 0x4753
|
||||
#define PCI_CHIP_MACH64GT 0x4754
|
||||
#define PCI_CHIP_MACH64GU 0x4755
|
||||
#define PCI_CHIP_MACH64GV 0x4756
|
||||
#define PCI_CHIP_MACH64GW 0x4757
|
||||
#define PCI_CHIP_MACH64GX 0x4758
|
||||
#define PCI_CHIP_MACH64GY 0x4759
|
||||
#define PCI_CHIP_MACH64GZ 0x475A
|
||||
#define PCI_CHIP_RV250_Id 0x4964
|
||||
#define PCI_CHIP_RV250_Ie 0x4965
|
||||
#define PCI_CHIP_RV250_If 0x4966
|
||||
#define PCI_CHIP_RV250_Ig 0x4967
|
||||
#define PCI_CHIP_R420_JH 0x4A48
|
||||
#define PCI_CHIP_R420_JI 0x4A49
|
||||
#define PCI_CHIP_R420_JJ 0x4A4A
|
||||
#define PCI_CHIP_R420_JK 0x4A4B
|
||||
#define PCI_CHIP_R420_JL 0x4A4C
|
||||
#define PCI_CHIP_R420_JM 0x4A4D
|
||||
#define PCI_CHIP_R420_JN 0x4A4E
|
||||
#define PCI_CHIP_R420_JP 0x4A50
|
||||
#define PCI_CHIP_MACH64LB 0x4C42
|
||||
#define PCI_CHIP_MACH64LD 0x4C44
|
||||
#define PCI_CHIP_RAGE128LE 0x4C45
|
||||
#define PCI_CHIP_RAGE128LF 0x4C46
|
||||
#define PCI_CHIP_MACH64LG 0x4C47
|
||||
#define PCI_CHIP_MACH64LI 0x4C49
|
||||
#define PCI_CHIP_MACH64LM 0x4C4D
|
||||
#define PCI_CHIP_MACH64LN 0x4C4E
|
||||
#define PCI_CHIP_MACH64LP 0x4C50
|
||||
#define PCI_CHIP_MACH64LQ 0x4C51
|
||||
#define PCI_CHIP_MACH64LR 0x4C52
|
||||
#define PCI_CHIP_MACH64LS 0x4C53
|
||||
#define PCI_CHIP_MACH64LT 0x4C54
|
||||
#define PCI_CHIP_RADEON_LW 0x4C57
|
||||
#define PCI_CHIP_RADEON_LX 0x4C58
|
||||
#define PCI_CHIP_RADEON_LY 0x4C59
|
||||
#define PCI_CHIP_RADEON_LZ 0x4C5A
|
||||
#define PCI_CHIP_RV250_Ld 0x4C64
|
||||
#define PCI_CHIP_RV250_Le 0x4C65
|
||||
#define PCI_CHIP_RV250_Lf 0x4C66
|
||||
#define PCI_CHIP_RV250_Lg 0x4C67
|
||||
#define PCI_CHIP_RV250_Ln 0x4C6E
|
||||
#define PCI_CHIP_RAGE128MF 0x4D46
|
||||
#define PCI_CHIP_RAGE128ML 0x4D4C
|
||||
#define PCI_CHIP_R300_ND 0x4E44
|
||||
#define PCI_CHIP_R300_NE 0x4E45
|
||||
#define PCI_CHIP_R300_NF 0x4E46
|
||||
#define PCI_CHIP_R300_NG 0x4E47
|
||||
#define PCI_CHIP_R350_NH 0x4E48
|
||||
#define PCI_CHIP_R350_NI 0x4E49
|
||||
#define PCI_CHIP_R360_NJ 0x4E4A
|
||||
#define PCI_CHIP_R350_NK 0x4E4B
|
||||
#define PCI_CHIP_RV350_NP 0x4E50
|
||||
#define PCI_CHIP_RV350_NQ 0x4E51
|
||||
#define PCI_CHIP_RV350_NR 0x4E52
|
||||
#define PCI_CHIP_RV350_NS 0x4E53
|
||||
#define PCI_CHIP_RV350_NT 0x4E54
|
||||
#define PCI_CHIP_RV350_NV 0x4E56
|
||||
#define PCI_CHIP_RAGE128PA 0x5041
|
||||
#define PCI_CHIP_RAGE128PB 0x5042
|
||||
#define PCI_CHIP_RAGE128PC 0x5043
|
||||
#define PCI_CHIP_RAGE128PD 0x5044
|
||||
#define PCI_CHIP_RAGE128PE 0x5045
|
||||
#define PCI_CHIP_RAGE128PF 0x5046
|
||||
#define PCI_CHIP_RAGE128PG 0x5047
|
||||
#define PCI_CHIP_RAGE128PH 0x5048
|
||||
#define PCI_CHIP_RAGE128PI 0x5049
|
||||
#define PCI_CHIP_RAGE128PJ 0x504A
|
||||
#define PCI_CHIP_RAGE128PK 0x504B
|
||||
#define PCI_CHIP_RAGE128PL 0x504C
|
||||
#define PCI_CHIP_RAGE128PM 0x504D
|
||||
#define PCI_CHIP_RAGE128PN 0x504E
|
||||
#define PCI_CHIP_RAGE128PO 0x504F
|
||||
#define PCI_CHIP_RAGE128PP 0x5050
|
||||
#define PCI_CHIP_RAGE128PQ 0x5051
|
||||
#define PCI_CHIP_RAGE128PR 0x5052
|
||||
#define PCI_CHIP_RAGE128PS 0x5053
|
||||
#define PCI_CHIP_RAGE128PT 0x5054
|
||||
#define PCI_CHIP_RAGE128PU 0x5055
|
||||
#define PCI_CHIP_RAGE128PV 0x5056
|
||||
#define PCI_CHIP_RAGE128PW 0x5057
|
||||
#define PCI_CHIP_RAGE128PX 0x5058
|
||||
#define PCI_CHIP_RADEON_QD 0x5144
|
||||
#define PCI_CHIP_RADEON_QE 0x5145
|
||||
#define PCI_CHIP_RADEON_QF 0x5146
|
||||
#define PCI_CHIP_RADEON_QG 0x5147
|
||||
#define PCI_CHIP_R200_QH 0x5148
|
||||
#define PCI_CHIP_R200_QI 0x5149
|
||||
#define PCI_CHIP_R200_QJ 0x514A
|
||||
#define PCI_CHIP_R200_QK 0x514B
|
||||
#define PCI_CHIP_R200_QL 0x514C
|
||||
#define PCI_CHIP_R200_QM 0x514D
|
||||
#define PCI_CHIP_R200_QN 0x514E
|
||||
#define PCI_CHIP_R200_QO 0x514F
|
||||
#define PCI_CHIP_RV200_QW 0x5157
|
||||
#define PCI_CHIP_RV200_QX 0x5158
|
||||
#define PCI_CHIP_RV100_QY 0x5159
|
||||
#define PCI_CHIP_RV100_QZ 0x515A
|
||||
#define PCI_CHIP_RN50 0x515E
|
||||
#define PCI_CHIP_RAGE128RE 0x5245
|
||||
#define PCI_CHIP_RAGE128RF 0x5246
|
||||
#define PCI_CHIP_RAGE128RG 0x5247
|
||||
#define PCI_CHIP_RAGE128RK 0x524B
|
||||
#define PCI_CHIP_RAGE128RL 0x524C
|
||||
#define PCI_CHIP_RAGE128SE 0x5345
|
||||
#define PCI_CHIP_RAGE128SF 0x5346
|
||||
#define PCI_CHIP_RAGE128SG 0x5347
|
||||
#define PCI_CHIP_RAGE128SH 0x5348
|
||||
#define PCI_CHIP_RAGE128SK 0x534B
|
||||
#define PCI_CHIP_RAGE128SL 0x534C
|
||||
#define PCI_CHIP_RAGE128SM 0x534D
|
||||
#define PCI_CHIP_RAGE128SN 0x534E
|
||||
#define PCI_CHIP_RAGE128TF 0x5446
|
||||
#define PCI_CHIP_RAGE128TL 0x544C
|
||||
#define PCI_CHIP_RAGE128TR 0x5452
|
||||
#define PCI_CHIP_RAGE128TS 0x5453
|
||||
#define PCI_CHIP_RAGE128TT 0x5454
|
||||
#define PCI_CHIP_RAGE128TU 0x5455
|
||||
#define PCI_CHIP_RV370_5460 0x5460
|
||||
#define PCI_CHIP_RV370_5461 0x5461
|
||||
#define PCI_CHIP_RV370_5462 0x5462
|
||||
#define PCI_CHIP_RV370_5463 0x5463
|
||||
#define PCI_CHIP_RV370_5464 0x5464
|
||||
#define PCI_CHIP_RV370_5465 0x5465
|
||||
#define PCI_CHIP_RV370_5466 0x5466
|
||||
#define PCI_CHIP_RV370_5467 0x5467
|
||||
#define PCI_CHIP_R423_UH 0x5548
|
||||
#define PCI_CHIP_R423_UI 0x5549
|
||||
#define PCI_CHIP_R423_UJ 0x554A
|
||||
#define PCI_CHIP_R423_UK 0x554B
|
||||
#define PCI_CHIP_R423_UQ 0x5551
|
||||
#define PCI_CHIP_R423_UR 0x5552
|
||||
#define PCI_CHIP_R423_UT 0x5554
|
||||
#define PCI_CHIP_MACH64VT 0x5654
|
||||
#define PCI_CHIP_MACH64VU 0x5655
|
||||
#define PCI_CHIP_MACH64VV 0x5656
|
||||
#define PCI_CHIP_RS300_5834 0x5834
|
||||
#define PCI_CHIP_RS300_5835 0x5835
|
||||
#define PCI_CHIP_RS300_5836 0x5836
|
||||
#define PCI_CHIP_RS300_5837 0x5837
|
||||
#define PCI_CHIP_RV370_5B60 0x5B60
|
||||
#define PCI_CHIP_RV370_5B61 0x5B61
|
||||
#define PCI_CHIP_RV370_5B62 0x5B62
|
||||
#define PCI_CHIP_RV370_5B63 0x5B63
|
||||
#define PCI_CHIP_RV370_5B64 0x5B64
|
||||
#define PCI_CHIP_RV370_5B65 0x5B65
|
||||
#define PCI_CHIP_RV370_5B66 0x5B66
|
||||
#define PCI_CHIP_RV370_5B67 0x5B67
|
||||
#define PCI_CHIP_RV280_5960 0x5960
|
||||
#define PCI_CHIP_RV280_5961 0x5961
|
||||
#define PCI_CHIP_RV280_5962 0x5962
|
||||
#define PCI_CHIP_RV280_5964 0x5964
|
||||
#define PCI_CHIP_RV280_5C61 0x5C61
|
||||
#define PCI_CHIP_RV280_5C63 0x5C63
|
||||
#define PCI_CHIP_R423_5D57 0x5D57
|
||||
#define PCI_CHIP_RS350_7834 0x7834
|
||||
#define PCI_CHIP_RS350_7835 0x7835
|
||||
|
|
@ -0,0 +1,781 @@
|
|||
/*
|
||||
* ATI Radeon Video card Framebuffer driver.
|
||||
*
|
||||
* Copyright 2007 Freescale Semiconductor, Inc.
|
||||
* Zhang Wei <wei.zhang@freescale.com>
|
||||
* Jason Jin <jason.jin@freescale.com>
|
||||
*
|
||||
* See file CREDITS for list of people who contributed to this
|
||||
* project.
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* Some codes of this file is partly ported from Linux kernel
|
||||
* ATI video framebuffer driver.
|
||||
*
|
||||
* Now the driver is tested on below ATI chips:
|
||||
* 9200
|
||||
* X300
|
||||
* X700
|
||||
*
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
|
||||
#include <command.h>
|
||||
#include <pci.h>
|
||||
#include <asm/processor.h>
|
||||
#include <asm/errno.h>
|
||||
#include <asm/io.h>
|
||||
#include <malloc.h>
|
||||
#include <video_fb.h>
|
||||
#include "videomodes.h"
|
||||
|
||||
#include <radeon.h>
|
||||
#include "ati_ids.h"
|
||||
#include "ati_radeon_fb.h"
|
||||
|
||||
#undef DEBUG
|
||||
|
||||
#ifdef DEBUG
|
||||
#define DPRINT(x...) printf(x)
|
||||
#else
|
||||
#define DPRINT(x...) do{}while(0)
|
||||
#endif
|
||||
|
||||
#ifndef min_t
|
||||
#define min_t(type,x,y) \
|
||||
({ type __x = (x); type __y = (y); __x < __y ? __x: __y; })
|
||||
#endif
|
||||
|
||||
#define MAX_MAPPED_VRAM (2048*2048*4)
|
||||
#define MIN_MAPPED_VRAM (1024*768*1)
|
||||
|
||||
#define RADEON_BUFFER_ALIGN 0x00000fff
|
||||
#define SURF_UPPER_BOUND(x,y,bpp) (((((x) * (((y) + 15) & ~15) * (bpp)/8) + RADEON_BUFFER_ALIGN) \
|
||||
& ~RADEON_BUFFER_ALIGN) - 1)
|
||||
#define RADEON_CRT_PITCH(width, bpp) ((((width) * (bpp) + ((bpp) * 8 - 1)) / ((bpp) * 8)) | \
|
||||
((((width) * (bpp) + ((bpp) * 8 - 1)) / ((bpp) * 8)) << 16))
|
||||
|
||||
#define CRTC_H_TOTAL_DISP_VAL(htotal, hdisp) \
|
||||
(((((htotal) / 8) - 1) & 0x3ff) | (((((hdisp) / 8) - 1) & 0x1ff) << 16))
|
||||
#define CRTC_HSYNC_STRT_WID_VAL(hsync_srtr, hsync_wid) \
|
||||
(((hsync_srtr) & 0x1fff) | (((hsync_wid) & 0x3f) << 16))
|
||||
#define CRTC_V_TOTAL_DISP_VAL(vtotal, vdisp) \
|
||||
((((vtotal) - 1) & 0xffff) | (((vdisp) - 1) << 16))
|
||||
#define CRTC_VSYNC_STRT_WID_VAL(vsync_srtr, vsync_wid) \
|
||||
((((vsync_srtr) - 1) & 0xfff) | (((vsync_wid) & 0x1f) << 16))
|
||||
|
||||
/*#define PCI_VENDOR_ID_ATI*/
|
||||
#define PCI_CHIP_RV280_5960 0x5960
|
||||
#define PCI_CHIP_RV280_5961 0x5961
|
||||
#define PCI_CHIP_RV280_5962 0x5962
|
||||
#define PCI_CHIP_RV280_5964 0x5964
|
||||
#define PCI_CHIP_RV280_5C63 0x5C63
|
||||
#define PCI_CHIP_RV370_5B60 0x5B60
|
||||
#define PCI_CHIP_RV380_5657 0x5657
|
||||
#define PCI_CHIP_R420_554d 0x554d
|
||||
|
||||
static struct pci_device_id ati_radeon_pci_ids[] = {
|
||||
{PCI_VENDOR_ID_ATI, PCI_CHIP_RV280_5960},
|
||||
{PCI_VENDOR_ID_ATI, PCI_CHIP_RV280_5961},
|
||||
{PCI_VENDOR_ID_ATI, PCI_CHIP_RV280_5962},
|
||||
{PCI_VENDOR_ID_ATI, PCI_CHIP_RV280_5964},
|
||||
{PCI_VENDOR_ID_ATI, PCI_CHIP_RV280_5C63},
|
||||
{PCI_VENDOR_ID_ATI, PCI_CHIP_RV370_5B60},
|
||||
{PCI_VENDOR_ID_ATI, PCI_CHIP_RV380_5657},
|
||||
{PCI_VENDOR_ID_ATI, PCI_CHIP_R420_554d},
|
||||
{0, 0}
|
||||
};
|
||||
|
||||
static u16 ati_radeon_id_family_table[][2] = {
|
||||
{PCI_CHIP_RV280_5960, CHIP_FAMILY_RV280},
|
||||
{PCI_CHIP_RV280_5961, CHIP_FAMILY_RV280},
|
||||
{PCI_CHIP_RV280_5962, CHIP_FAMILY_RV280},
|
||||
{PCI_CHIP_RV280_5964, CHIP_FAMILY_RV280},
|
||||
{PCI_CHIP_RV280_5C63, CHIP_FAMILY_RV280},
|
||||
{PCI_CHIP_RV370_5B60, CHIP_FAMILY_RV380},
|
||||
{PCI_CHIP_RV380_5657, CHIP_FAMILY_RV380},
|
||||
{PCI_CHIP_R420_554d, CHIP_FAMILY_R420},
|
||||
{0, 0}
|
||||
};
|
||||
|
||||
u16 get_radeon_id_family(u16 device)
|
||||
{
|
||||
int i;
|
||||
for (i=0; ati_radeon_id_family_table[0][i]; i+=2)
|
||||
if (ati_radeon_id_family_table[0][i] == device)
|
||||
return ati_radeon_id_family_table[0][i + 1];
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct radeonfb_info *rinfo;
|
||||
|
||||
static void radeon_identify_vram(struct radeonfb_info *rinfo)
|
||||
{
|
||||
u32 tmp;
|
||||
|
||||
/* framebuffer size */
|
||||
if ((rinfo->family == CHIP_FAMILY_RS100) ||
|
||||
(rinfo->family == CHIP_FAMILY_RS200) ||
|
||||
(rinfo->family == CHIP_FAMILY_RS300)) {
|
||||
u32 tom = INREG(NB_TOM);
|
||||
tmp = ((((tom >> 16) - (tom & 0xffff) + 1) << 6) * 1024);
|
||||
|
||||
radeon_fifo_wait(6);
|
||||
OUTREG(MC_FB_LOCATION, tom);
|
||||
OUTREG(DISPLAY_BASE_ADDR, (tom & 0xffff) << 16);
|
||||
OUTREG(CRTC2_DISPLAY_BASE_ADDR, (tom & 0xffff) << 16);
|
||||
OUTREG(OV0_BASE_ADDR, (tom & 0xffff) << 16);
|
||||
|
||||
/* This is supposed to fix the crtc2 noise problem. */
|
||||
OUTREG(GRPH2_BUFFER_CNTL, INREG(GRPH2_BUFFER_CNTL) & ~0x7f0000);
|
||||
|
||||
if ((rinfo->family == CHIP_FAMILY_RS100) ||
|
||||
(rinfo->family == CHIP_FAMILY_RS200)) {
|
||||
/* This is to workaround the asic bug for RMX, some versions
|
||||
of BIOS dosen't have this register initialized correctly.
|
||||
*/
|
||||
OUTREGP(CRTC_MORE_CNTL, CRTC_H_CUTOFF_ACTIVE_EN,
|
||||
~CRTC_H_CUTOFF_ACTIVE_EN);
|
||||
}
|
||||
} else {
|
||||
tmp = INREG(CONFIG_MEMSIZE);
|
||||
}
|
||||
|
||||
/* mem size is bits [28:0], mask off the rest */
|
||||
rinfo->video_ram = tmp & CONFIG_MEMSIZE_MASK;
|
||||
|
||||
/*
|
||||
* Hack to get around some busted production M6's
|
||||
* reporting no ram
|
||||
*/
|
||||
if (rinfo->video_ram == 0) {
|
||||
switch (rinfo->pdev.device) {
|
||||
case PCI_CHIP_RADEON_LY:
|
||||
case PCI_CHIP_RADEON_LZ:
|
||||
rinfo->video_ram = 8192 * 1024;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Now try to identify VRAM type
|
||||
*/
|
||||
if ((rinfo->family >= CHIP_FAMILY_R300) ||
|
||||
(INREG(MEM_SDRAM_MODE_REG) & (1<<30)))
|
||||
rinfo->vram_ddr = 1;
|
||||
else
|
||||
rinfo->vram_ddr = 0;
|
||||
|
||||
tmp = INREG(MEM_CNTL);
|
||||
if (IS_R300_VARIANT(rinfo)) {
|
||||
tmp &= R300_MEM_NUM_CHANNELS_MASK;
|
||||
switch (tmp) {
|
||||
case 0: rinfo->vram_width = 64; break;
|
||||
case 1: rinfo->vram_width = 128; break;
|
||||
case 2: rinfo->vram_width = 256; break;
|
||||
default: rinfo->vram_width = 128; break;
|
||||
}
|
||||
} else if ((rinfo->family == CHIP_FAMILY_RV100) ||
|
||||
(rinfo->family == CHIP_FAMILY_RS100) ||
|
||||
(rinfo->family == CHIP_FAMILY_RS200)){
|
||||
if (tmp & RV100_MEM_HALF_MODE)
|
||||
rinfo->vram_width = 32;
|
||||
else
|
||||
rinfo->vram_width = 64;
|
||||
} else {
|
||||
if (tmp & MEM_NUM_CHANNELS_MASK)
|
||||
rinfo->vram_width = 128;
|
||||
else
|
||||
rinfo->vram_width = 64;
|
||||
}
|
||||
|
||||
/* This may not be correct, as some cards can have half of channel disabled
|
||||
* ToDo: identify these cases
|
||||
*/
|
||||
|
||||
DPRINT("radeonfb: Found %dk of %s %d bits wide videoram\n",
|
||||
rinfo->video_ram / 1024,
|
||||
rinfo->vram_ddr ? "DDR" : "SDRAM",
|
||||
rinfo->vram_width);
|
||||
|
||||
}
|
||||
|
||||
static void radeon_write_pll_regs(struct radeonfb_info *rinfo, struct radeon_regs *mode)
|
||||
{
|
||||
int i;
|
||||
|
||||
radeon_fifo_wait(20);
|
||||
|
||||
#if 0
|
||||
/* Workaround from XFree */
|
||||
if (rinfo->is_mobility) {
|
||||
/* A temporal workaround for the occational blanking on certain laptop
|
||||
* panels. This appears to related to the PLL divider registers
|
||||
* (fail to lock?). It occurs even when all dividers are the same
|
||||
* with their old settings. In this case we really don't need to
|
||||
* fiddle with PLL registers. By doing this we can avoid the blanking
|
||||
* problem with some panels.
|
||||
*/
|
||||
if ((mode->ppll_ref_div == (INPLL(PPLL_REF_DIV) & PPLL_REF_DIV_MASK)) &&
|
||||
(mode->ppll_div_3 == (INPLL(PPLL_DIV_3) &
|
||||
(PPLL_POST3_DIV_MASK | PPLL_FB3_DIV_MASK)))) {
|
||||
/* We still have to force a switch to selected PPLL div thanks to
|
||||
* an XFree86 driver bug which will switch it away in some cases
|
||||
* even when using UseFDev */
|
||||
OUTREGP(CLOCK_CNTL_INDEX,
|
||||
mode->clk_cntl_index & PPLL_DIV_SEL_MASK,
|
||||
~PPLL_DIV_SEL_MASK);
|
||||
radeon_pll_errata_after_index(rinfo);
|
||||
radeon_pll_errata_after_data(rinfo);
|
||||
return;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
if(rinfo->pdev.device == PCI_CHIP_RV370_5B60) return;
|
||||
|
||||
/* Swich VCKL clock input to CPUCLK so it stays fed while PPLL updates*/
|
||||
OUTPLLP(VCLK_ECP_CNTL, VCLK_SRC_SEL_CPUCLK, ~VCLK_SRC_SEL_MASK);
|
||||
|
||||
/* Reset PPLL & enable atomic update */
|
||||
OUTPLLP(PPLL_CNTL,
|
||||
PPLL_RESET | PPLL_ATOMIC_UPDATE_EN | PPLL_VGA_ATOMIC_UPDATE_EN,
|
||||
~(PPLL_RESET | PPLL_ATOMIC_UPDATE_EN | PPLL_VGA_ATOMIC_UPDATE_EN));
|
||||
|
||||
/* Switch to selected PPLL divider */
|
||||
OUTREGP(CLOCK_CNTL_INDEX,
|
||||
mode->clk_cntl_index & PPLL_DIV_SEL_MASK,
|
||||
~PPLL_DIV_SEL_MASK);
|
||||
|
||||
/* Set PPLL ref. div */
|
||||
if (rinfo->family == CHIP_FAMILY_R300 ||
|
||||
rinfo->family == CHIP_FAMILY_RS300 ||
|
||||
rinfo->family == CHIP_FAMILY_R350 ||
|
||||
rinfo->family == CHIP_FAMILY_RV350) {
|
||||
if (mode->ppll_ref_div & R300_PPLL_REF_DIV_ACC_MASK) {
|
||||
/* When restoring console mode, use saved PPLL_REF_DIV
|
||||
* setting.
|
||||
*/
|
||||
OUTPLLP(PPLL_REF_DIV, mode->ppll_ref_div, 0);
|
||||
} else {
|
||||
/* R300 uses ref_div_acc field as real ref divider */
|
||||
OUTPLLP(PPLL_REF_DIV,
|
||||
(mode->ppll_ref_div << R300_PPLL_REF_DIV_ACC_SHIFT),
|
||||
~R300_PPLL_REF_DIV_ACC_MASK);
|
||||
}
|
||||
} else
|
||||
OUTPLLP(PPLL_REF_DIV, mode->ppll_ref_div, ~PPLL_REF_DIV_MASK);
|
||||
|
||||
/* Set PPLL divider 3 & post divider*/
|
||||
OUTPLLP(PPLL_DIV_3, mode->ppll_div_3, ~PPLL_FB3_DIV_MASK);
|
||||
OUTPLLP(PPLL_DIV_3, mode->ppll_div_3, ~PPLL_POST3_DIV_MASK);
|
||||
|
||||
/* Write update */
|
||||
while (INPLL(PPLL_REF_DIV) & PPLL_ATOMIC_UPDATE_R)
|
||||
;
|
||||
OUTPLLP(PPLL_REF_DIV, PPLL_ATOMIC_UPDATE_W, ~PPLL_ATOMIC_UPDATE_W);
|
||||
|
||||
/* Wait read update complete */
|
||||
/* FIXME: Certain revisions of R300 can't recover here. Not sure of
|
||||
the cause yet, but this workaround will mask the problem for now.
|
||||
Other chips usually will pass at the very first test, so the
|
||||
workaround shouldn't have any effect on them. */
|
||||
for (i = 0; (i < 10000 && INPLL(PPLL_REF_DIV) & PPLL_ATOMIC_UPDATE_R); i++)
|
||||
;
|
||||
|
||||
OUTPLL(HTOTAL_CNTL, 0);
|
||||
|
||||
/* Clear reset & atomic update */
|
||||
OUTPLLP(PPLL_CNTL, 0,
|
||||
~(PPLL_RESET | PPLL_SLEEP | PPLL_ATOMIC_UPDATE_EN | PPLL_VGA_ATOMIC_UPDATE_EN));
|
||||
|
||||
/* We may want some locking ... oh well */
|
||||
udelay(5000);
|
||||
|
||||
/* Switch back VCLK source to PPLL */
|
||||
OUTPLLP(VCLK_ECP_CNTL, VCLK_SRC_SEL_PPLLCLK, ~VCLK_SRC_SEL_MASK);
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
u16 reg;
|
||||
u32 val;
|
||||
} reg_val;
|
||||
|
||||
#if 0 /* unused ? -> scheduled for removal */
|
||||
/* these common regs are cleared before mode setting so they do not
|
||||
* interfere with anything
|
||||
*/
|
||||
static reg_val common_regs[] = {
|
||||
{ OVR_CLR, 0 },
|
||||
{ OVR_WID_LEFT_RIGHT, 0 },
|
||||
{ OVR_WID_TOP_BOTTOM, 0 },
|
||||
{ OV0_SCALE_CNTL, 0 },
|
||||
{ SUBPIC_CNTL, 0 },
|
||||
{ VIPH_CONTROL, 0 },
|
||||
{ I2C_CNTL_1, 0 },
|
||||
{ GEN_INT_CNTL, 0 },
|
||||
{ CAP0_TRIG_CNTL, 0 },
|
||||
{ CAP1_TRIG_CNTL, 0 },
|
||||
};
|
||||
#endif /* 0 */
|
||||
|
||||
void radeon_setmode(void)
|
||||
{
|
||||
struct radeon_regs *mode = malloc(sizeof(struct radeon_regs));
|
||||
|
||||
mode->crtc_gen_cntl = 0x03000200;
|
||||
mode->crtc_ext_cntl = 0x00008048;
|
||||
mode->dac_cntl = 0xff002100;
|
||||
mode->crtc_h_total_disp = 0x4f0063;
|
||||
mode->crtc_h_sync_strt_wid = 0x8c02a2;
|
||||
mode->crtc_v_total_disp = 0x01df020c;
|
||||
mode->crtc_v_sync_strt_wid = 0x8201ea;
|
||||
mode->crtc_pitch = 0x00500050;
|
||||
|
||||
OUTREG(CRTC_GEN_CNTL, mode->crtc_gen_cntl);
|
||||
OUTREGP(CRTC_EXT_CNTL, mode->crtc_ext_cntl,
|
||||
~(CRTC_HSYNC_DIS | CRTC_VSYNC_DIS | CRTC_DISPLAY_DIS));
|
||||
OUTREGP(DAC_CNTL, mode->dac_cntl, DAC_RANGE_CNTL | DAC_BLANKING);
|
||||
OUTREG(CRTC_H_TOTAL_DISP, mode->crtc_h_total_disp);
|
||||
OUTREG(CRTC_H_SYNC_STRT_WID, mode->crtc_h_sync_strt_wid);
|
||||
OUTREG(CRTC_V_TOTAL_DISP, mode->crtc_v_total_disp);
|
||||
OUTREG(CRTC_V_SYNC_STRT_WID, mode->crtc_v_sync_strt_wid);
|
||||
OUTREG(CRTC_OFFSET, 0);
|
||||
OUTREG(CRTC_OFFSET_CNTL, 0);
|
||||
OUTREG(CRTC_PITCH, mode->crtc_pitch);
|
||||
|
||||
mode->clk_cntl_index = 0x300;
|
||||
mode->ppll_ref_div = 0xc;
|
||||
mode->ppll_div_3 = 0x00030059;
|
||||
|
||||
radeon_write_pll_regs(rinfo, mode);
|
||||
}
|
||||
|
||||
static void set_pal(void)
|
||||
{
|
||||
int idx, val = 0;
|
||||
|
||||
for (idx = 0; idx < 256; idx++) {
|
||||
OUTREG8(PALETTE_INDEX, idx);
|
||||
OUTREG(PALETTE_DATA, val);
|
||||
val += 0x00010101;
|
||||
}
|
||||
}
|
||||
|
||||
void radeon_setmode_9200(int vesa_idx, int bpp)
|
||||
{
|
||||
struct radeon_regs *mode = malloc(sizeof(struct radeon_regs));
|
||||
|
||||
mode->crtc_gen_cntl = CRTC_EN | CRTC_EXT_DISP_EN;
|
||||
mode->crtc_ext_cntl = VGA_ATI_LINEAR | XCRT_CNT_EN | CRTC_CRT_ON;
|
||||
mode->dac_cntl = DAC_MASK_ALL | DAC_VGA_ADR_EN | DAC_8BIT_EN;
|
||||
mode->crtc_offset_cntl = CRTC_OFFSET_CNTL__CRTC_TILE_EN;
|
||||
|
||||
switch (bpp) {
|
||||
case 24:
|
||||
mode->crtc_gen_cntl |= 0x6 << 8; /* x888 */
|
||||
#if defined(__BIG_ENDIAN)
|
||||
mode->surface_cntl = NONSURF_AP0_SWP_32BPP | NONSURF_AP1_SWP_32BPP;
|
||||
mode->surf_info[0] = NONSURF_AP0_SWP_32BPP | NONSURF_AP1_SWP_32BPP;
|
||||
#endif
|
||||
break;
|
||||
case 16:
|
||||
mode->crtc_gen_cntl |= 0x4 << 8; /* 565 */
|
||||
#if defined(__BIG_ENDIAN)
|
||||
mode->surface_cntl = NONSURF_AP0_SWP_16BPP | NONSURF_AP1_SWP_16BPP;
|
||||
mode->surf_info[0] = NONSURF_AP0_SWP_16BPP | NONSURF_AP1_SWP_16BPP;
|
||||
#endif
|
||||
break;
|
||||
default:
|
||||
mode->crtc_gen_cntl |= 0x2 << 8; /* palette */
|
||||
mode->surface_cntl = 0x00000000;
|
||||
break;
|
||||
}
|
||||
|
||||
switch (vesa_idx) {
|
||||
case RES_MODE_1280x1024:
|
||||
mode->crtc_h_total_disp = CRTC_H_TOTAL_DISP_VAL(1688,1280);
|
||||
mode->crtc_v_total_disp = CRTC_V_TOTAL_DISP_VAL(1066,1024);
|
||||
mode->crtc_v_sync_strt_wid = CRTC_VSYNC_STRT_WID_VAL(1025,3);
|
||||
#if defined(CONFIG_RADEON_VREFRESH_75HZ)
|
||||
mode->crtc_h_sync_strt_wid = CRTC_HSYNC_STRT_WID_VAL(1288,18);
|
||||
mode->ppll_div_3 = 0x00010078;
|
||||
#else /* default @ 60 Hz */
|
||||
mode->crtc_h_sync_strt_wid = CRTC_HSYNC_STRT_WID_VAL(1320,14);
|
||||
mode->ppll_div_3 = 0x00010060;
|
||||
#endif
|
||||
/*
|
||||
* for this mode pitch expands to the same value for 32, 16 and 8 bpp,
|
||||
* so we set it here once only.
|
||||
*/
|
||||
mode->crtc_pitch = RADEON_CRT_PITCH(1280,32);
|
||||
switch (bpp) {
|
||||
case 24:
|
||||
mode->surf_info[0] |= R200_SURF_TILE_COLOR_MACRO | (1280 * 4 / 16);
|
||||
mode->surf_upper_bound[0] = SURF_UPPER_BOUND(1280,1024,32);
|
||||
break;
|
||||
case 16:
|
||||
mode->surf_info[0] |= R200_SURF_TILE_COLOR_MACRO | (1280 * 2 / 16);
|
||||
mode->surf_upper_bound[0] = SURF_UPPER_BOUND(1280,1024,16);
|
||||
break;
|
||||
default: /* 8 bpp */
|
||||
mode->surf_info[0] = R200_SURF_TILE_COLOR_MACRO | (1280 * 1 / 16);
|
||||
mode->surf_upper_bound[0] = SURF_UPPER_BOUND(1280,1024,8);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case RES_MODE_1024x768:
|
||||
#if defined(CONFIG_RADEON_VREFRESH_75HZ)
|
||||
mode->crtc_h_total_disp = CRTC_H_TOTAL_DISP_VAL(1312,1024);
|
||||
mode->crtc_h_sync_strt_wid = CRTC_HSYNC_STRT_WID_VAL(1032,12);
|
||||
mode->crtc_v_total_disp = CRTC_V_TOTAL_DISP_VAL(800,768);
|
||||
mode->crtc_v_sync_strt_wid = CRTC_VSYNC_STRT_WID_VAL(769,3);
|
||||
mode->ppll_div_3 = 0x0002008c;
|
||||
#else /* @ 60 Hz */
|
||||
mode->crtc_h_total_disp = CRTC_H_TOTAL_DISP_VAL(1344,1024);
|
||||
mode->crtc_h_sync_strt_wid = CRTC_HSYNC_STRT_WID_VAL(1040,17) | CRTC_H_SYNC_POL;
|
||||
mode->crtc_v_total_disp = CRTC_V_TOTAL_DISP_VAL(806,768);
|
||||
mode->crtc_v_sync_strt_wid = CRTC_VSYNC_STRT_WID_VAL(771,6) | CRTC_V_SYNC_POL;
|
||||
mode->ppll_div_3 = 0x00020074;
|
||||
#endif
|
||||
/* also same pitch value for 32, 16 and 8 bpp */
|
||||
mode->crtc_pitch = RADEON_CRT_PITCH(1024,32);
|
||||
switch (bpp) {
|
||||
case 24:
|
||||
mode->surf_info[0] |= R200_SURF_TILE_COLOR_MACRO | (1024 * 4 / 16);
|
||||
mode->surf_upper_bound[0] = SURF_UPPER_BOUND(1024,768,32);
|
||||
break;
|
||||
case 16:
|
||||
mode->surf_info[0] |= R200_SURF_TILE_COLOR_MACRO | (1024 * 2 / 16);
|
||||
mode->surf_upper_bound[0] = SURF_UPPER_BOUND(1024,768,16);
|
||||
break;
|
||||
default: /* 8 bpp */
|
||||
mode->surf_info[0] = R200_SURF_TILE_COLOR_MACRO | (1024 * 1 / 16);
|
||||
mode->surf_upper_bound[0] = SURF_UPPER_BOUND(1024,768,8);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case RES_MODE_800x600:
|
||||
mode->crtc_h_total_disp = CRTC_H_TOTAL_DISP_VAL(1056,800);
|
||||
#if defined(CONFIG_RADEON_VREFRESH_75HZ)
|
||||
mode->crtc_h_sync_strt_wid = CRTC_HSYNC_STRT_WID_VAL(808,10);
|
||||
mode->crtc_v_total_disp = CRTC_V_TOTAL_DISP_VAL(625,600);
|
||||
mode->crtc_v_sync_strt_wid = CRTC_VSYNC_STRT_WID_VAL(601,3);
|
||||
mode->ppll_div_3 = 0x000300b0;
|
||||
#else /* @ 60 Hz */
|
||||
mode->crtc_h_sync_strt_wid = CRTC_HSYNC_STRT_WID_VAL(832,16);
|
||||
mode->crtc_v_total_disp = CRTC_V_TOTAL_DISP_VAL(628,600);
|
||||
mode->crtc_v_sync_strt_wid = CRTC_VSYNC_STRT_WID_VAL(601,4);
|
||||
mode->ppll_div_3 = 0x0003008e;
|
||||
#endif
|
||||
switch (bpp) {
|
||||
case 24:
|
||||
mode->crtc_pitch = RADEON_CRT_PITCH(832,32);
|
||||
mode->surf_info[0] |= R200_SURF_TILE_COLOR_MACRO | (832 * 4 / 16);
|
||||
mode->surf_upper_bound[0] = SURF_UPPER_BOUND(832,600,32);
|
||||
break;
|
||||
case 16:
|
||||
mode->crtc_pitch = RADEON_CRT_PITCH(896,16);
|
||||
mode->surf_info[0] |= R200_SURF_TILE_COLOR_MACRO | (896 * 2 / 16);
|
||||
mode->surf_upper_bound[0] = SURF_UPPER_BOUND(896,600,16);
|
||||
break;
|
||||
default: /* 8 bpp */
|
||||
mode->crtc_pitch = RADEON_CRT_PITCH(1024,8);
|
||||
mode->surf_info[0] = R200_SURF_TILE_COLOR_MACRO | (1024 * 1 / 16);
|
||||
mode->surf_upper_bound[0] = SURF_UPPER_BOUND(1024,600,8);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
default: /* RES_MODE_640x480 */
|
||||
#if defined(CONFIG_RADEON_VREFRESH_75HZ)
|
||||
mode->crtc_h_total_disp = CRTC_H_TOTAL_DISP_VAL(840,640);
|
||||
mode->crtc_h_sync_strt_wid = CRTC_HSYNC_STRT_WID_VAL(648,8) | CRTC_H_SYNC_POL;
|
||||
mode->crtc_v_total_disp = CRTC_V_TOTAL_DISP_VAL(500,480);
|
||||
mode->crtc_v_sync_strt_wid = CRTC_VSYNC_STRT_WID_VAL(481,3) | CRTC_V_SYNC_POL;
|
||||
mode->ppll_div_3 = 0x00030070;
|
||||
#else /* @ 60 Hz */
|
||||
mode->crtc_h_total_disp = CRTC_H_TOTAL_DISP_VAL(800,640);
|
||||
mode->crtc_h_sync_strt_wid = CRTC_HSYNC_STRT_WID_VAL(674,12) | CRTC_H_SYNC_POL;
|
||||
mode->crtc_v_total_disp = CRTC_V_TOTAL_DISP_VAL(525,480);
|
||||
mode->crtc_v_sync_strt_wid = CRTC_VSYNC_STRT_WID_VAL(491,2) | CRTC_V_SYNC_POL;
|
||||
mode->ppll_div_3 = 0x00030059;
|
||||
#endif
|
||||
/* also same pitch value for 32, 16 and 8 bpp */
|
||||
mode->crtc_pitch = RADEON_CRT_PITCH(640,32);
|
||||
switch (bpp) {
|
||||
case 24:
|
||||
mode->surf_info[0] |= R200_SURF_TILE_COLOR_MACRO | (640 * 4 / 16);
|
||||
mode->surf_upper_bound[0] = SURF_UPPER_BOUND(640,480,32);
|
||||
break;
|
||||
case 16:
|
||||
mode->surf_info[0] |= R200_SURF_TILE_COLOR_MACRO | (640 * 2 / 16);
|
||||
mode->surf_upper_bound[0] = SURF_UPPER_BOUND(640,480,16);
|
||||
break;
|
||||
default: /* 8 bpp */
|
||||
mode->crtc_offset_cntl = 0x00000000;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
OUTREG(CRTC_GEN_CNTL, mode->crtc_gen_cntl | CRTC_DISP_REQ_EN_B);
|
||||
OUTREGP(CRTC_EXT_CNTL, mode->crtc_ext_cntl,
|
||||
(CRTC_HSYNC_DIS | CRTC_VSYNC_DIS | CRTC_DISPLAY_DIS));
|
||||
OUTREGP(DAC_CNTL, mode->dac_cntl, DAC_RANGE_CNTL | DAC_BLANKING);
|
||||
OUTREG(CRTC_H_TOTAL_DISP, mode->crtc_h_total_disp);
|
||||
OUTREG(CRTC_H_SYNC_STRT_WID, mode->crtc_h_sync_strt_wid);
|
||||
OUTREG(CRTC_V_TOTAL_DISP, mode->crtc_v_total_disp);
|
||||
OUTREG(CRTC_V_SYNC_STRT_WID, mode->crtc_v_sync_strt_wid);
|
||||
OUTREG(CRTC_OFFSET, 0);
|
||||
OUTREG(CRTC_OFFSET_CNTL, mode->crtc_offset_cntl);
|
||||
OUTREG(CRTC_PITCH, mode->crtc_pitch);
|
||||
OUTREG(CRTC_GEN_CNTL, mode->crtc_gen_cntl);
|
||||
|
||||
mode->clk_cntl_index = 0x300;
|
||||
mode->ppll_ref_div = 0xc;
|
||||
|
||||
radeon_write_pll_regs(rinfo, mode);
|
||||
|
||||
OUTREGP(CRTC_EXT_CNTL, mode->crtc_ext_cntl,
|
||||
~(CRTC_HSYNC_DIS | CRTC_VSYNC_DIS | CRTC_DISPLAY_DIS));
|
||||
OUTREG(SURFACE0_INFO, mode->surf_info[0]);
|
||||
OUTREG(SURFACE0_LOWER_BOUND, 0);
|
||||
OUTREG(SURFACE0_UPPER_BOUND, mode->surf_upper_bound[0]);
|
||||
OUTREG(SURFACE_CNTL, mode->surface_cntl);
|
||||
|
||||
if (bpp > 8)
|
||||
set_pal();
|
||||
|
||||
free(mode);
|
||||
}
|
||||
|
||||
#include "../bios_emulator/include/biosemu.h"
|
||||
extern int BootVideoCardBIOS(pci_dev_t pcidev, BE_VGAInfo ** pVGAInfo, int cleanUp);
|
||||
|
||||
int radeon_probe(struct radeonfb_info *rinfo)
|
||||
{
|
||||
pci_dev_t pdev;
|
||||
u16 did;
|
||||
|
||||
pdev = pci_find_devices(ati_radeon_pci_ids, 0);
|
||||
|
||||
if (pdev != -1) {
|
||||
pci_read_config_word(pdev, PCI_DEVICE_ID, &did);
|
||||
printf("ATI Radeon video card (%04x, %04x) found @(%d:%d:%d)\n",
|
||||
PCI_VENDOR_ID_ATI, did, (pdev >> 16) & 0xff,
|
||||
(pdev >> 11) & 0x1f, (pdev >> 8) & 0x7);
|
||||
|
||||
strcpy(rinfo->name, "ATI Radeon");
|
||||
rinfo->pdev.vendor = PCI_VENDOR_ID_ATI;
|
||||
rinfo->pdev.device = did;
|
||||
rinfo->family = get_radeon_id_family(rinfo->pdev.device);
|
||||
pci_read_config_dword(pdev, PCI_BASE_ADDRESS_0,
|
||||
&rinfo->fb_base_bus);
|
||||
pci_read_config_dword(pdev, PCI_BASE_ADDRESS_2,
|
||||
&rinfo->mmio_base_bus);
|
||||
rinfo->fb_base_bus &= 0xfffff000;
|
||||
rinfo->mmio_base_bus &= ~0x04;
|
||||
|
||||
rinfo->mmio_base = pci_bus_to_virt(pdev, rinfo->mmio_base_bus,
|
||||
PCI_REGION_MEM, 0, MAP_NOCACHE);
|
||||
DPRINT("rinfo->mmio_base = 0x%p bus=0x%x\n",
|
||||
rinfo->mmio_base, rinfo->mmio_base_bus);
|
||||
rinfo->fb_local_base = INREG(MC_FB_LOCATION) << 16;
|
||||
DPRINT("rinfo->fb_local_base = 0x%x\n",rinfo->fb_local_base);
|
||||
/* PostBIOS with x86 emulater */
|
||||
if (!BootVideoCardBIOS(pdev, NULL, 0))
|
||||
return -1;
|
||||
|
||||
/*
|
||||
* Check for errata
|
||||
* (These will be added in the future for the chipfamily
|
||||
* R300, RV200, RS200, RV100, RS100.)
|
||||
*/
|
||||
|
||||
/* Get VRAM size and type */
|
||||
radeon_identify_vram(rinfo);
|
||||
|
||||
rinfo->mapped_vram = min_t(unsigned long, MAX_MAPPED_VRAM,
|
||||
rinfo->video_ram);
|
||||
rinfo->fb_base = pci_bus_to_virt(pdev, rinfo->fb_base_bus,
|
||||
PCI_REGION_MEM, 0, MAP_NOCACHE);
|
||||
DPRINT("Radeon: framebuffer base address 0x%08x, "
|
||||
"bus address 0x%08x\n"
|
||||
"MMIO base address 0x%08x, bus address 0x%08x, "
|
||||
"framebuffer local base 0x%08x.\n ",
|
||||
(u32)rinfo->fb_base, rinfo->fb_base_bus,
|
||||
(u32)rinfo->mmio_base, rinfo->mmio_base_bus,
|
||||
rinfo->fb_local_base);
|
||||
return 0;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
* The Graphic Device
|
||||
*/
|
||||
GraphicDevice ctfb;
|
||||
|
||||
#define CURSOR_SIZE 0x1000 /* in KByte for HW Cursor */
|
||||
#define PATTERN_ADR (pGD->dprBase + CURSOR_SIZE) /* pattern Memory after Cursor Memory */
|
||||
#define PATTERN_SIZE 8*8*4 /* 4 Bytes per Pixel 8 x 8 Pixel */
|
||||
#define ACCELMEMORY (CURSOR_SIZE + PATTERN_SIZE) /* reserved Memory for BITBlt and hw cursor */
|
||||
|
||||
void *video_hw_init(void)
|
||||
{
|
||||
GraphicDevice *pGD = (GraphicDevice *) & ctfb;
|
||||
u32 *vm;
|
||||
char *penv;
|
||||
unsigned long t1, hsynch, vsynch;
|
||||
int bits_per_pixel, i, tmp, vesa_idx = 0, videomode;
|
||||
struct ctfb_res_modes *res_mode;
|
||||
struct ctfb_res_modes var_mode;
|
||||
|
||||
rinfo = malloc(sizeof(struct radeonfb_info));
|
||||
|
||||
printf("Video: ");
|
||||
if(radeon_probe(rinfo)) {
|
||||
printf("No radeon video card found!\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
tmp = 0;
|
||||
|
||||
videomode = CONFIG_SYS_DEFAULT_VIDEO_MODE;
|
||||
/* get video mode via environment */
|
||||
if ((penv = getenv ("videomode")) != NULL) {
|
||||
/* deceide if it is a string */
|
||||
if (penv[0] <= '9') {
|
||||
videomode = (int) simple_strtoul (penv, NULL, 16);
|
||||
tmp = 1;
|
||||
}
|
||||
} else {
|
||||
tmp = 1;
|
||||
}
|
||||
if (tmp) {
|
||||
/* parameter are vesa modes */
|
||||
/* search params */
|
||||
for (i = 0; i < VESA_MODES_COUNT; i++) {
|
||||
if (vesa_modes[i].vesanr == videomode)
|
||||
break;
|
||||
}
|
||||
if (i == VESA_MODES_COUNT) {
|
||||
printf ("no VESA Mode found, switching to mode 0x%x ", CONFIG_SYS_DEFAULT_VIDEO_MODE);
|
||||
i = 0;
|
||||
}
|
||||
res_mode = (struct ctfb_res_modes *) &res_mode_init[vesa_modes[i].resindex];
|
||||
bits_per_pixel = vesa_modes[i].bits_per_pixel;
|
||||
vesa_idx = vesa_modes[i].resindex;
|
||||
} else {
|
||||
res_mode = (struct ctfb_res_modes *) &var_mode;
|
||||
bits_per_pixel = video_get_params (res_mode, penv);
|
||||
}
|
||||
|
||||
/* calculate hsynch and vsynch freq (info only) */
|
||||
t1 = (res_mode->left_margin + res_mode->xres +
|
||||
res_mode->right_margin + res_mode->hsync_len) / 8;
|
||||
t1 *= 8;
|
||||
t1 *= res_mode->pixclock;
|
||||
t1 /= 1000;
|
||||
hsynch = 1000000000L / t1;
|
||||
t1 *= (res_mode->upper_margin + res_mode->yres +
|
||||
res_mode->lower_margin + res_mode->vsync_len);
|
||||
t1 /= 1000;
|
||||
vsynch = 1000000000L / t1;
|
||||
|
||||
/* fill in Graphic device struct */
|
||||
sprintf (pGD->modeIdent, "%dx%dx%d %ldkHz %ldHz", res_mode->xres,
|
||||
res_mode->yres, bits_per_pixel, (hsynch / 1000),
|
||||
(vsynch / 1000));
|
||||
printf ("%s\n", pGD->modeIdent);
|
||||
pGD->winSizeX = res_mode->xres;
|
||||
pGD->winSizeY = res_mode->yres;
|
||||
pGD->plnSizeX = res_mode->xres;
|
||||
pGD->plnSizeY = res_mode->yres;
|
||||
|
||||
switch (bits_per_pixel) {
|
||||
case 24:
|
||||
pGD->gdfBytesPP = 4;
|
||||
pGD->gdfIndex = GDF_32BIT_X888RGB;
|
||||
if (res_mode->xres == 800) {
|
||||
pGD->winSizeX = 832;
|
||||
pGD->plnSizeX = 832;
|
||||
}
|
||||
break;
|
||||
case 16:
|
||||
pGD->gdfBytesPP = 2;
|
||||
pGD->gdfIndex = GDF_16BIT_565RGB;
|
||||
if (res_mode->xres == 800) {
|
||||
pGD->winSizeX = 896;
|
||||
pGD->plnSizeX = 896;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
if (res_mode->xres == 800) {
|
||||
pGD->winSizeX = 1024;
|
||||
pGD->plnSizeX = 1024;
|
||||
}
|
||||
pGD->gdfBytesPP = 1;
|
||||
pGD->gdfIndex = GDF__8BIT_INDEX;
|
||||
break;
|
||||
}
|
||||
|
||||
pGD->isaBase = CONFIG_SYS_ISA_IO_BASE_ADDRESS;
|
||||
pGD->pciBase = (unsigned int)rinfo->fb_base;
|
||||
pGD->frameAdrs = (unsigned int)rinfo->fb_base;
|
||||
pGD->memSize = 64 * 1024 * 1024;
|
||||
|
||||
/* Cursor Start Address */
|
||||
pGD->dprBase = (pGD->winSizeX * pGD->winSizeY * pGD->gdfBytesPP) +
|
||||
(unsigned int)rinfo->fb_base;
|
||||
if ((pGD->dprBase & 0x0fff) != 0) {
|
||||
/* allign it */
|
||||
pGD->dprBase &= 0xfffff000;
|
||||
pGD->dprBase += 0x00001000;
|
||||
}
|
||||
DPRINT ("Cursor Start %x Pattern Start %x\n", pGD->dprBase,
|
||||
PATTERN_ADR);
|
||||
pGD->vprBase = (unsigned int)rinfo->fb_base; /* Dummy */
|
||||
pGD->cprBase = (unsigned int)rinfo->fb_base; /* Dummy */
|
||||
/* set up Hardware */
|
||||
|
||||
/* Clear video memory (only visible screen area) */
|
||||
i = pGD->winSizeX * pGD->winSizeY * pGD->gdfBytesPP / 4;
|
||||
vm = (unsigned int *) pGD->pciBase;
|
||||
while (i--)
|
||||
*vm++ = 0;
|
||||
/*SetDrawingEngine (bits_per_pixel);*/
|
||||
|
||||
if (rinfo->family == CHIP_FAMILY_RV280)
|
||||
radeon_setmode_9200(vesa_idx, bits_per_pixel);
|
||||
else
|
||||
radeon_setmode();
|
||||
|
||||
return ((void *) pGD);
|
||||
}
|
||||
|
||||
void video_set_lut (unsigned int index, /* color number */
|
||||
unsigned char r, /* red */
|
||||
unsigned char g, /* green */
|
||||
unsigned char b /* blue */
|
||||
)
|
||||
{
|
||||
OUTREG(PALETTE_INDEX, index);
|
||||
OUTREG(PALETTE_DATA, (r << 16) | (g << 8) | b);
|
||||
}
|
||||
|
|
@ -0,0 +1,282 @@
|
|||
#ifndef __ATI_RADEON_FB_H
|
||||
#define __ATI_RADEON_FB_H
|
||||
|
||||
/***************************************************************
|
||||
* Most of the definitions here are adapted right from XFree86 *
|
||||
***************************************************************/
|
||||
|
||||
/*
|
||||
* Chip families. Must fit in the low 16 bits of a long word
|
||||
*/
|
||||
enum radeon_family {
|
||||
CHIP_FAMILY_UNKNOW,
|
||||
CHIP_FAMILY_LEGACY,
|
||||
CHIP_FAMILY_RADEON,
|
||||
CHIP_FAMILY_RV100,
|
||||
CHIP_FAMILY_RS100, /* U1 (IGP320M) or A3 (IGP320)*/
|
||||
CHIP_FAMILY_RV200,
|
||||
CHIP_FAMILY_RS200, /* U2 (IGP330M/340M/350M) or A4 (IGP330/340/345/350),
|
||||
RS250 (IGP 7000) */
|
||||
CHIP_FAMILY_R200,
|
||||
CHIP_FAMILY_RV250,
|
||||
CHIP_FAMILY_RS300, /* Radeon 9000 IGP */
|
||||
CHIP_FAMILY_RV280,
|
||||
CHIP_FAMILY_R300,
|
||||
CHIP_FAMILY_R350,
|
||||
CHIP_FAMILY_RV350,
|
||||
CHIP_FAMILY_RV380, /* RV370/RV380/M22/M24 */
|
||||
CHIP_FAMILY_R420, /* R420/R423/M18 */
|
||||
CHIP_FAMILY_LAST,
|
||||
};
|
||||
|
||||
#define IS_RV100_VARIANT(rinfo) (((rinfo)->family == CHIP_FAMILY_RV100) || \
|
||||
((rinfo)->family == CHIP_FAMILY_RV200) || \
|
||||
((rinfo)->family == CHIP_FAMILY_RS100) || \
|
||||
((rinfo)->family == CHIP_FAMILY_RS200) || \
|
||||
((rinfo)->family == CHIP_FAMILY_RV250) || \
|
||||
((rinfo)->family == CHIP_FAMILY_RV280) || \
|
||||
((rinfo)->family == CHIP_FAMILY_RS300))
|
||||
|
||||
#define IS_R300_VARIANT(rinfo) (((rinfo)->family == CHIP_FAMILY_R300) || \
|
||||
((rinfo)->family == CHIP_FAMILY_RV350) || \
|
||||
((rinfo)->family == CHIP_FAMILY_R350) || \
|
||||
((rinfo)->family == CHIP_FAMILY_RV380) || \
|
||||
((rinfo)->family == CHIP_FAMILY_R420))
|
||||
|
||||
struct radeonfb_info {
|
||||
char name[20];
|
||||
|
||||
struct pci_device_id pdev;
|
||||
u16 family;
|
||||
|
||||
u32 fb_base_bus;
|
||||
u32 mmio_base_bus;
|
||||
|
||||
void *mmio_base;
|
||||
void *fb_base;
|
||||
|
||||
u32 video_ram;
|
||||
u32 mapped_vram;
|
||||
int vram_width;
|
||||
int vram_ddr;
|
||||
|
||||
u32 fb_local_base;
|
||||
};
|
||||
|
||||
#define INREG8(addr) readb((rinfo->mmio_base)+addr)
|
||||
#define OUTREG8(addr,val) writeb(val, (rinfo->mmio_base)+addr)
|
||||
#define INREG16(addr) readw((rinfo->mmio_base)+addr)
|
||||
#define OUTREG16(addr,val) writew(val, (rinfo->mmio_base)+addr)
|
||||
#define INREG(addr) readl((rinfo->mmio_base)+addr)
|
||||
#define OUTREG(addr,val) writel(val, (rinfo->mmio_base)+addr)
|
||||
|
||||
static inline void _OUTREGP(struct radeonfb_info *rinfo, u32 addr,
|
||||
u32 val, u32 mask)
|
||||
{
|
||||
unsigned int tmp;
|
||||
|
||||
tmp = INREG(addr);
|
||||
tmp &= (mask);
|
||||
tmp |= (val);
|
||||
OUTREG(addr, tmp);
|
||||
}
|
||||
|
||||
#define OUTREGP(addr,val,mask) _OUTREGP(rinfo, addr, val,mask)
|
||||
|
||||
/*
|
||||
* 2D Engine helper routines
|
||||
*/
|
||||
static inline void radeon_engine_flush (struct radeonfb_info *rinfo)
|
||||
{
|
||||
int i;
|
||||
|
||||
/* initiate flush */
|
||||
OUTREGP(RB2D_DSTCACHE_CTLSTAT, RB2D_DC_FLUSH_ALL,
|
||||
~RB2D_DC_FLUSH_ALL);
|
||||
|
||||
for (i=0; i < 2000000; i++) {
|
||||
if (!(INREG(RB2D_DSTCACHE_CTLSTAT) & RB2D_DC_BUSY))
|
||||
return;
|
||||
udelay(1);
|
||||
}
|
||||
printf("radeonfb: Flush Timeout !\n");
|
||||
}
|
||||
|
||||
static inline void _radeon_fifo_wait(struct radeonfb_info *rinfo, int entries)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i=0; i<2000000; i++) {
|
||||
if ((INREG(RBBM_STATUS) & 0x7f) >= entries)
|
||||
return;
|
||||
udelay(1);
|
||||
}
|
||||
printf("radeonfb: FIFO Timeout !\n");
|
||||
}
|
||||
|
||||
static inline void _radeon_engine_idle(struct radeonfb_info *rinfo)
|
||||
{
|
||||
int i;
|
||||
|
||||
/* ensure FIFO is empty before waiting for idle */
|
||||
_radeon_fifo_wait (rinfo, 64);
|
||||
|
||||
for (i=0; i<2000000; i++) {
|
||||
if (((INREG(RBBM_STATUS) & GUI_ACTIVE)) == 0) {
|
||||
radeon_engine_flush (rinfo);
|
||||
return;
|
||||
}
|
||||
udelay(1);
|
||||
}
|
||||
printf("radeonfb: Idle Timeout !\n");
|
||||
}
|
||||
|
||||
#define radeon_engine_idle() _radeon_engine_idle(rinfo)
|
||||
#define radeon_fifo_wait(entries) _radeon_fifo_wait(rinfo,entries)
|
||||
#define radeon_msleep(ms) _radeon_msleep(rinfo,ms)
|
||||
|
||||
/*
|
||||
* This structure contains the various registers manipulated by this
|
||||
* driver for setting or restoring a mode. It's mostly copied from
|
||||
* XFree's RADEONSaveRec structure. A few chip settings might still be
|
||||
* tweaked without beeing reflected or saved in these registers though
|
||||
*/
|
||||
struct radeon_regs {
|
||||
/* Common registers */
|
||||
u32 ovr_clr;
|
||||
u32 ovr_wid_left_right;
|
||||
u32 ovr_wid_top_bottom;
|
||||
u32 ov0_scale_cntl;
|
||||
u32 mpp_tb_config;
|
||||
u32 mpp_gp_config;
|
||||
u32 subpic_cntl;
|
||||
u32 viph_control;
|
||||
u32 i2c_cntl_1;
|
||||
u32 gen_int_cntl;
|
||||
u32 cap0_trig_cntl;
|
||||
u32 cap1_trig_cntl;
|
||||
u32 bus_cntl;
|
||||
u32 surface_cntl;
|
||||
u32 bios_5_scratch;
|
||||
|
||||
/* Other registers to save for VT switches or driver load/unload */
|
||||
u32 dp_datatype;
|
||||
u32 rbbm_soft_reset;
|
||||
u32 clock_cntl_index;
|
||||
u32 amcgpio_en_reg;
|
||||
u32 amcgpio_mask;
|
||||
|
||||
/* Surface/tiling registers */
|
||||
u32 surf_lower_bound[8];
|
||||
u32 surf_upper_bound[8];
|
||||
u32 surf_info[8];
|
||||
|
||||
/* CRTC registers */
|
||||
u32 crtc_gen_cntl;
|
||||
u32 crtc_ext_cntl;
|
||||
u32 dac_cntl;
|
||||
u32 crtc_h_total_disp;
|
||||
u32 crtc_h_sync_strt_wid;
|
||||
u32 crtc_v_total_disp;
|
||||
u32 crtc_v_sync_strt_wid;
|
||||
u32 crtc_offset;
|
||||
u32 crtc_offset_cntl;
|
||||
u32 crtc_pitch;
|
||||
u32 disp_merge_cntl;
|
||||
u32 grph_buffer_cntl;
|
||||
u32 crtc_more_cntl;
|
||||
|
||||
/* CRTC2 registers */
|
||||
u32 crtc2_gen_cntl;
|
||||
u32 dac2_cntl;
|
||||
u32 disp_output_cntl;
|
||||
u32 disp_hw_debug;
|
||||
u32 disp2_merge_cntl;
|
||||
u32 grph2_buffer_cntl;
|
||||
u32 crtc2_h_total_disp;
|
||||
u32 crtc2_h_sync_strt_wid;
|
||||
u32 crtc2_v_total_disp;
|
||||
u32 crtc2_v_sync_strt_wid;
|
||||
u32 crtc2_offset;
|
||||
u32 crtc2_offset_cntl;
|
||||
u32 crtc2_pitch;
|
||||
|
||||
/* Flat panel regs */
|
||||
u32 fp_crtc_h_total_disp;
|
||||
u32 fp_crtc_v_total_disp;
|
||||
u32 fp_gen_cntl;
|
||||
u32 fp2_gen_cntl;
|
||||
u32 fp_h_sync_strt_wid;
|
||||
u32 fp2_h_sync_strt_wid;
|
||||
u32 fp_horz_stretch;
|
||||
u32 fp_panel_cntl;
|
||||
u32 fp_v_sync_strt_wid;
|
||||
u32 fp2_v_sync_strt_wid;
|
||||
u32 fp_vert_stretch;
|
||||
u32 lvds_gen_cntl;
|
||||
u32 lvds_pll_cntl;
|
||||
u32 tmds_crc;
|
||||
u32 tmds_transmitter_cntl;
|
||||
|
||||
/* Computed values for PLL */
|
||||
u32 dot_clock_freq;
|
||||
int feedback_div;
|
||||
int post_div;
|
||||
|
||||
/* PLL registers */
|
||||
u32 ppll_div_3;
|
||||
u32 ppll_ref_div;
|
||||
u32 vclk_ecp_cntl;
|
||||
u32 clk_cntl_index;
|
||||
|
||||
/* Computed values for PLL2 */
|
||||
u32 dot_clock_freq_2;
|
||||
int feedback_div_2;
|
||||
int post_div_2;
|
||||
|
||||
/* PLL2 registers */
|
||||
u32 p2pll_ref_div;
|
||||
u32 p2pll_div_0;
|
||||
u32 htotal_cntl2;
|
||||
|
||||
/* Palette */
|
||||
int palette_valid;
|
||||
};
|
||||
|
||||
static inline u32 __INPLL(struct radeonfb_info *rinfo, u32 addr)
|
||||
{
|
||||
u32 data;
|
||||
|
||||
OUTREG8(CLOCK_CNTL_INDEX, addr & 0x0000003f);
|
||||
/* radeon_pll_errata_after_index(rinfo); */
|
||||
data = INREG(CLOCK_CNTL_DATA);
|
||||
/* radeon_pll_errata_after_data(rinfo); */
|
||||
return data;
|
||||
}
|
||||
|
||||
static inline void __OUTPLL(struct radeonfb_info *rinfo, unsigned int index,
|
||||
u32 val)
|
||||
{
|
||||
|
||||
OUTREG8(CLOCK_CNTL_INDEX, (index & 0x0000003f) | 0x00000080);
|
||||
/* radeon_pll_errata_after_index(rinfo); */
|
||||
OUTREG(CLOCK_CNTL_DATA, val);
|
||||
/* radeon_pll_errata_after_data(rinfo); */
|
||||
}
|
||||
|
||||
static inline void __OUTPLLP(struct radeonfb_info *rinfo, unsigned int index,
|
||||
u32 val, u32 mask)
|
||||
{
|
||||
unsigned int tmp;
|
||||
|
||||
tmp = __INPLL(rinfo, index);
|
||||
tmp &= (mask);
|
||||
tmp |= (val);
|
||||
__OUTPLL(rinfo, index, tmp);
|
||||
}
|
||||
|
||||
#define INPLL(addr) __INPLL(rinfo, addr)
|
||||
#define OUTPLL(index, val) __OUTPLL(rinfo, index, val)
|
||||
#define OUTPLLP(index, val, mask) __OUTPLLP(rinfo, index, val, mask)
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,211 @@
|
|||
/*
|
||||
* Driver for AT91/AT32 MULTI LAYER LCD Controller
|
||||
*
|
||||
* Copyright (C) 2012 Atmel Corporation
|
||||
*
|
||||
* See file CREDITS for list of people who contributed to this
|
||||
* project.
|
||||
*
|
||||
* 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 <common.h>
|
||||
#include <asm/io.h>
|
||||
#include <asm/arch/gpio.h>
|
||||
#include <asm/arch/clk.h>
|
||||
#include <lcd.h>
|
||||
#include <atmel_hlcdc.h>
|
||||
|
||||
int lcd_line_length;
|
||||
int lcd_color_fg;
|
||||
int lcd_color_bg;
|
||||
|
||||
void *lcd_base; /* Start of framebuffer memory */
|
||||
void *lcd_console_address; /* Start of console buffer */
|
||||
|
||||
short console_col;
|
||||
short console_row;
|
||||
|
||||
/* configurable parameters */
|
||||
#define ATMEL_LCDC_CVAL_DEFAULT 0xc8
|
||||
#define ATMEL_LCDC_DMA_BURST_LEN 8
|
||||
#ifndef ATMEL_LCDC_GUARD_TIME
|
||||
#define ATMEL_LCDC_GUARD_TIME 1
|
||||
#endif
|
||||
|
||||
#define ATMEL_LCDC_FIFO_SIZE 512
|
||||
|
||||
#define lcdc_readl(reg) __raw_readl((reg))
|
||||
#define lcdc_writel(reg, val) __raw_writel((val), (reg))
|
||||
|
||||
void lcd_ctrl_init(void *lcdbase)
|
||||
{
|
||||
unsigned long value;
|
||||
struct lcd_dma_desc *desc;
|
||||
struct atmel_hlcd_regs *regs;
|
||||
|
||||
if (!has_lcdc())
|
||||
return; /* No lcdc */
|
||||
|
||||
regs = (struct atmel_hlcd_regs *)panel_info.mmio;
|
||||
|
||||
/* Disable DISP signal */
|
||||
lcdc_writel(®s->lcdc_lcddis, LCDC_LCDDIS_DISPDIS);
|
||||
while ((lcdc_readl(®s->lcdc_lcdsr) & LCDC_LCDSR_DISPSTS))
|
||||
udelay(1);
|
||||
/* Disable synchronization */
|
||||
lcdc_writel(®s->lcdc_lcddis, LCDC_LCDDIS_SYNCDIS);
|
||||
while ((lcdc_readl(®s->lcdc_lcdsr) & LCDC_LCDSR_LCDSTS))
|
||||
udelay(1);
|
||||
/* Disable pixel clock */
|
||||
lcdc_writel(®s->lcdc_lcddis, LCDC_LCDDIS_CLKDIS);
|
||||
while ((lcdc_readl(®s->lcdc_lcdsr) & LCDC_LCDSR_CLKSTS))
|
||||
udelay(1);
|
||||
/* Disable PWM */
|
||||
lcdc_writel(®s->lcdc_lcddis, LCDC_LCDDIS_PWMDIS);
|
||||
while ((lcdc_readl(®s->lcdc_lcdsr) & LCDC_LCDSR_PWMSTS))
|
||||
udelay(1);
|
||||
|
||||
/* Set pixel clock */
|
||||
value = get_lcdc_clk_rate(0) / panel_info.vl_clk;
|
||||
if (get_lcdc_clk_rate(0) % panel_info.vl_clk)
|
||||
value++;
|
||||
|
||||
if (value < 1) {
|
||||
/* Using system clock as pixel clock */
|
||||
lcdc_writel(®s->lcdc_lcdcfg0,
|
||||
LCDC_LCDCFG0_CLKDIV(0)
|
||||
| LCDC_LCDCFG0_CGDISHCR
|
||||
| LCDC_LCDCFG0_CGDISHEO
|
||||
| LCDC_LCDCFG0_CGDISOVR1
|
||||
| LCDC_LCDCFG0_CGDISBASE
|
||||
| panel_info.vl_clk_pol
|
||||
| LCDC_LCDCFG0_CLKSEL);
|
||||
|
||||
} else {
|
||||
lcdc_writel(®s->lcdc_lcdcfg0,
|
||||
LCDC_LCDCFG0_CLKDIV(value - 2)
|
||||
| LCDC_LCDCFG0_CGDISHCR
|
||||
| LCDC_LCDCFG0_CGDISHEO
|
||||
| LCDC_LCDCFG0_CGDISOVR1
|
||||
| LCDC_LCDCFG0_CGDISBASE
|
||||
| panel_info.vl_clk_pol);
|
||||
}
|
||||
|
||||
/* Initialize control register 5 */
|
||||
value = 0;
|
||||
|
||||
value |= panel_info.vl_sync;
|
||||
|
||||
#ifndef LCD_OUTPUT_BPP
|
||||
/* Output is 24bpp */
|
||||
value |= LCDC_LCDCFG5_MODE_OUTPUT_24BPP;
|
||||
#else
|
||||
switch (LCD_OUTPUT_BPP) {
|
||||
case 12:
|
||||
value |= LCDC_LCDCFG5_MODE_OUTPUT_12BPP;
|
||||
break;
|
||||
case 16:
|
||||
value |= LCDC_LCDCFG5_MODE_OUTPUT_16BPP;
|
||||
break;
|
||||
case 18:
|
||||
value |= LCDC_LCDCFG5_MODE_OUTPUT_18BPP;
|
||||
break;
|
||||
case 24:
|
||||
value |= LCDC_LCDCFG5_MODE_OUTPUT_24BPP;
|
||||
break;
|
||||
default:
|
||||
BUG();
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
|
||||
value |= LCDC_LCDCFG5_GUARDTIME(ATMEL_LCDC_GUARD_TIME);
|
||||
value |= (LCDC_LCDCFG5_DISPDLY | LCDC_LCDCFG5_VSPDLYS);
|
||||
lcdc_writel(®s->lcdc_lcdcfg5, value);
|
||||
|
||||
/* Vertical & Horizontal Timing */
|
||||
value = LCDC_LCDCFG1_VSPW(panel_info.vl_vsync_len - 1);
|
||||
value |= LCDC_LCDCFG1_HSPW(panel_info.vl_hsync_len - 1);
|
||||
lcdc_writel(®s->lcdc_lcdcfg1, value);
|
||||
|
||||
value = LCDC_LCDCFG2_VBPW(panel_info.vl_lower_margin);
|
||||
value |= LCDC_LCDCFG2_VFPW(panel_info.vl_upper_margin - 1);
|
||||
lcdc_writel(®s->lcdc_lcdcfg2, value);
|
||||
|
||||
value = LCDC_LCDCFG3_HBPW(panel_info.vl_right_margin - 1);
|
||||
value |= LCDC_LCDCFG3_HFPW(panel_info.vl_left_margin - 1);
|
||||
lcdc_writel(®s->lcdc_lcdcfg3, value);
|
||||
|
||||
/* Display size */
|
||||
value = LCDC_LCDCFG4_RPF(panel_info.vl_row - 1);
|
||||
value |= LCDC_LCDCFG4_PPL(panel_info.vl_col - 1);
|
||||
lcdc_writel(®s->lcdc_lcdcfg4, value);
|
||||
|
||||
lcdc_writel(®s->lcdc_basecfg0,
|
||||
LCDC_BASECFG0_BLEN_AHB_INCR4 | LCDC_BASECFG0_DLBO);
|
||||
|
||||
switch (NBITS(panel_info.vl_bpix)) {
|
||||
case 16:
|
||||
lcdc_writel(®s->lcdc_basecfg1,
|
||||
LCDC_BASECFG1_RGBMODE_16BPP_RGB_565);
|
||||
break;
|
||||
default:
|
||||
BUG();
|
||||
break;
|
||||
}
|
||||
|
||||
lcdc_writel(®s->lcdc_basecfg2, LCDC_BASECFG2_XSTRIDE(0));
|
||||
lcdc_writel(®s->lcdc_basecfg3, 0);
|
||||
lcdc_writel(®s->lcdc_basecfg4, LCDC_BASECFG4_DMA);
|
||||
|
||||
/* Disable all interrupts */
|
||||
lcdc_writel(®s->lcdc_lcdidr, ~0UL);
|
||||
lcdc_writel(®s->lcdc_baseidr, ~0UL);
|
||||
|
||||
/* Setup the DMA descriptor, this descriptor will loop to itself */
|
||||
desc = (struct lcd_dma_desc *)(lcdbase - 16);
|
||||
|
||||
desc->address = (u32)lcdbase;
|
||||
/* Disable DMA transfer interrupt & descriptor loaded interrupt. */
|
||||
desc->control = LCDC_BASECTRL_ADDIEN | LCDC_BASECTRL_DSCRIEN
|
||||
| LCDC_BASECTRL_DMAIEN | LCDC_BASECTRL_DFETCH;
|
||||
desc->next = (u32)desc;
|
||||
|
||||
lcdc_writel(®s->lcdc_baseaddr, desc->address);
|
||||
lcdc_writel(®s->lcdc_basectrl, desc->control);
|
||||
lcdc_writel(®s->lcdc_basenext, desc->next);
|
||||
lcdc_writel(®s->lcdc_basecher, LCDC_BASECHER_CHEN |
|
||||
LCDC_BASECHER_UPDATEEN);
|
||||
|
||||
/* Enable LCD */
|
||||
value = lcdc_readl(®s->lcdc_lcden);
|
||||
lcdc_writel(®s->lcdc_lcden, value | LCDC_LCDEN_CLKEN);
|
||||
while (!(lcdc_readl(®s->lcdc_lcdsr) & LCDC_LCDSR_CLKSTS))
|
||||
udelay(1);
|
||||
value = lcdc_readl(®s->lcdc_lcden);
|
||||
lcdc_writel(®s->lcdc_lcden, value | LCDC_LCDEN_SYNCEN);
|
||||
while (!(lcdc_readl(®s->lcdc_lcdsr) & LCDC_LCDSR_LCDSTS))
|
||||
udelay(1);
|
||||
value = lcdc_readl(®s->lcdc_lcden);
|
||||
lcdc_writel(®s->lcdc_lcden, value | LCDC_LCDEN_DISPEN);
|
||||
while (!(lcdc_readl(®s->lcdc_lcdsr) & LCDC_LCDSR_DISPSTS))
|
||||
udelay(1);
|
||||
value = lcdc_readl(®s->lcdc_lcden);
|
||||
lcdc_writel(®s->lcdc_lcden, value | LCDC_LCDEN_PWMEN);
|
||||
while (!(lcdc_readl(®s->lcdc_lcdsr) & LCDC_LCDSR_PWMSTS))
|
||||
udelay(1);
|
||||
}
|
||||
|
|
@ -0,0 +1,164 @@
|
|||
/*
|
||||
* Driver for AT91/AT32 LCD Controller
|
||||
*
|
||||
* Copyright (C) 2007 Atmel Corporation
|
||||
*
|
||||
* See file CREDITS for list of people who contributed to this
|
||||
* project.
|
||||
*
|
||||
* 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 <common.h>
|
||||
#include <asm/io.h>
|
||||
#include <asm/arch/gpio.h>
|
||||
#include <asm/arch/clk.h>
|
||||
#include <lcd.h>
|
||||
#include <atmel_lcdc.h>
|
||||
|
||||
int lcd_line_length;
|
||||
int lcd_color_fg;
|
||||
int lcd_color_bg;
|
||||
|
||||
void *lcd_base; /* Start of framebuffer memory */
|
||||
void *lcd_console_address; /* Start of console buffer */
|
||||
|
||||
short console_col;
|
||||
short console_row;
|
||||
|
||||
/* configurable parameters */
|
||||
#define ATMEL_LCDC_CVAL_DEFAULT 0xc8
|
||||
#define ATMEL_LCDC_DMA_BURST_LEN 8
|
||||
#ifndef ATMEL_LCDC_GUARD_TIME
|
||||
#define ATMEL_LCDC_GUARD_TIME 1
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_AT91SAM9263) || defined(CONFIG_AT91CAP9)
|
||||
#define ATMEL_LCDC_FIFO_SIZE 2048
|
||||
#else
|
||||
#define ATMEL_LCDC_FIFO_SIZE 512
|
||||
#endif
|
||||
|
||||
#define lcdc_readl(mmio, reg) __raw_readl((mmio)+(reg))
|
||||
#define lcdc_writel(mmio, reg, val) __raw_writel((val), (mmio)+(reg))
|
||||
|
||||
void lcd_setcolreg(ushort regno, ushort red, ushort green, ushort blue)
|
||||
{
|
||||
#if defined(CONFIG_ATMEL_LCD_BGR555)
|
||||
lcdc_writel(panel_info.mmio, ATMEL_LCDC_LUT(regno),
|
||||
(red >> 3) | ((green & 0xf8) << 2) | ((blue & 0xf8) << 7));
|
||||
#else
|
||||
lcdc_writel(panel_info.mmio, ATMEL_LCDC_LUT(regno),
|
||||
(blue >> 3) | ((green & 0xfc) << 3) | ((red & 0xf8) << 8));
|
||||
#endif
|
||||
}
|
||||
|
||||
void lcd_ctrl_init(void *lcdbase)
|
||||
{
|
||||
unsigned long value;
|
||||
|
||||
/* Turn off the LCD controller and the DMA controller */
|
||||
lcdc_writel(panel_info.mmio, ATMEL_LCDC_PWRCON,
|
||||
ATMEL_LCDC_GUARD_TIME << ATMEL_LCDC_GUARDT_OFFSET);
|
||||
|
||||
/* Wait for the LCDC core to become idle */
|
||||
while (lcdc_readl(panel_info.mmio, ATMEL_LCDC_PWRCON) & ATMEL_LCDC_BUSY)
|
||||
udelay(10);
|
||||
|
||||
lcdc_writel(panel_info.mmio, ATMEL_LCDC_DMACON, 0);
|
||||
|
||||
/* Reset LCDC DMA */
|
||||
lcdc_writel(panel_info.mmio, ATMEL_LCDC_DMACON, ATMEL_LCDC_DMARST);
|
||||
|
||||
/* ...set frame size and burst length = 8 words (?) */
|
||||
value = (panel_info.vl_col * panel_info.vl_row *
|
||||
NBITS(panel_info.vl_bpix)) / 32;
|
||||
value |= ((ATMEL_LCDC_DMA_BURST_LEN - 1) << ATMEL_LCDC_BLENGTH_OFFSET);
|
||||
lcdc_writel(panel_info.mmio, ATMEL_LCDC_DMAFRMCFG, value);
|
||||
|
||||
/* Set pixel clock */
|
||||
value = get_lcdc_clk_rate(0) / panel_info.vl_clk;
|
||||
if (get_lcdc_clk_rate(0) % panel_info.vl_clk)
|
||||
value++;
|
||||
value = (value / 2) - 1;
|
||||
|
||||
if (!value) {
|
||||
lcdc_writel(panel_info.mmio, ATMEL_LCDC_LCDCON1, ATMEL_LCDC_BYPASS);
|
||||
} else
|
||||
lcdc_writel(panel_info.mmio, ATMEL_LCDC_LCDCON1,
|
||||
value << ATMEL_LCDC_CLKVAL_OFFSET);
|
||||
|
||||
/* Initialize control register 2 */
|
||||
#ifdef CONFIG_AVR32
|
||||
value = ATMEL_LCDC_MEMOR_BIG | ATMEL_LCDC_CLKMOD_ALWAYSACTIVE;
|
||||
#else
|
||||
value = ATMEL_LCDC_MEMOR_LITTLE | ATMEL_LCDC_CLKMOD_ALWAYSACTIVE;
|
||||
#endif
|
||||
if (panel_info.vl_tft)
|
||||
value |= ATMEL_LCDC_DISTYPE_TFT;
|
||||
|
||||
value |= panel_info.vl_sync;
|
||||
value |= (panel_info.vl_bpix << 5);
|
||||
lcdc_writel(panel_info.mmio, ATMEL_LCDC_LCDCON2, value);
|
||||
|
||||
/* Vertical timing */
|
||||
value = (panel_info.vl_vsync_len - 1) << ATMEL_LCDC_VPW_OFFSET;
|
||||
value |= panel_info.vl_upper_margin << ATMEL_LCDC_VBP_OFFSET;
|
||||
value |= panel_info.vl_lower_margin;
|
||||
lcdc_writel(panel_info.mmio, ATMEL_LCDC_TIM1, value);
|
||||
|
||||
/* Horizontal timing */
|
||||
value = (panel_info.vl_right_margin - 1) << ATMEL_LCDC_HFP_OFFSET;
|
||||
value |= (panel_info.vl_hsync_len - 1) << ATMEL_LCDC_HPW_OFFSET;
|
||||
value |= (panel_info.vl_left_margin - 1);
|
||||
lcdc_writel(panel_info.mmio, ATMEL_LCDC_TIM2, value);
|
||||
|
||||
/* Display size */
|
||||
value = (panel_info.vl_col - 1) << ATMEL_LCDC_HOZVAL_OFFSET;
|
||||
value |= panel_info.vl_row - 1;
|
||||
lcdc_writel(panel_info.mmio, ATMEL_LCDC_LCDFRMCFG, value);
|
||||
|
||||
/* FIFO Threshold: Use formula from data sheet */
|
||||
value = ATMEL_LCDC_FIFO_SIZE - (2 * ATMEL_LCDC_DMA_BURST_LEN + 3);
|
||||
lcdc_writel(panel_info.mmio, ATMEL_LCDC_FIFO, value);
|
||||
|
||||
/* Toggle LCD_MODE every frame */
|
||||
lcdc_writel(panel_info.mmio, ATMEL_LCDC_MVAL, 0);
|
||||
|
||||
/* Disable all interrupts */
|
||||
lcdc_writel(panel_info.mmio, ATMEL_LCDC_IDR, ~0UL);
|
||||
|
||||
/* Set contrast */
|
||||
value = ATMEL_LCDC_PS_DIV8 |
|
||||
ATMEL_LCDC_ENA_PWMENABLE;
|
||||
if (!panel_info.vl_cont_pol_low)
|
||||
value |= ATMEL_LCDC_POL_POSITIVE;
|
||||
lcdc_writel(panel_info.mmio, ATMEL_LCDC_CONTRAST_CTR, value);
|
||||
lcdc_writel(panel_info.mmio, ATMEL_LCDC_CONTRAST_VAL, ATMEL_LCDC_CVAL_DEFAULT);
|
||||
|
||||
/* Set framebuffer DMA base address and pixel offset */
|
||||
lcdc_writel(panel_info.mmio, ATMEL_LCDC_DMABADDR1, (u_long)lcdbase);
|
||||
|
||||
lcdc_writel(panel_info.mmio, ATMEL_LCDC_DMACON, ATMEL_LCDC_DMAEN);
|
||||
lcdc_writel(panel_info.mmio, ATMEL_LCDC_PWRCON,
|
||||
(ATMEL_LCDC_GUARD_TIME << ATMEL_LCDC_GUARDT_OFFSET) | ATMEL_LCDC_PWR);
|
||||
}
|
||||
|
||||
ulong calc_fbsize(void)
|
||||
{
|
||||
return ((panel_info.vl_col * panel_info.vl_row *
|
||||
NBITS(panel_info.vl_bpix)) / 8) + PAGE_SIZE;
|
||||
}
|
||||
457
common/package/boot/uboot-ipq40xx/src/drivers/video/bus_vcxk.c
Normal file
457
common/package/boot/uboot-ipq40xx/src/drivers/video/bus_vcxk.c
Normal file
|
|
@ -0,0 +1,457 @@
|
|||
/*
|
||||
* (C) Copyright 2005-2009
|
||||
* Jens Scharsig @ BuS Elektronik GmbH & Co. KG, <esw@bus-elektronik.de>
|
||||
*
|
||||
* See file CREDITS for list of people who contributed to this
|
||||
* project.
|
||||
*
|
||||
* 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 <common.h>
|
||||
#include <bmp_layout.h>
|
||||
#include <asm/io.h>
|
||||
|
||||
vu_char *vcxk_bws = ((vu_char *) (CONFIG_SYS_VCXK_BASE));
|
||||
vu_short *vcxk_bws_word = ((vu_short *)(CONFIG_SYS_VCXK_BASE));
|
||||
vu_long *vcxk_bws_long = ((vu_long *) (CONFIG_SYS_VCXK_BASE));
|
||||
|
||||
#ifdef CONFIG_AT91RM9200
|
||||
#include <asm/arch/hardware.h>
|
||||
#include <asm/arch/at91_pio.h>
|
||||
|
||||
#ifndef VCBITMASK
|
||||
#define VCBITMASK(bitno) (0x0001 << (bitno % 16))
|
||||
#endif
|
||||
#ifndef CONFIG_AT91_LEGACY
|
||||
at91_pio_t *pio = (at91_pio_t *) AT91_PIO_BASE;
|
||||
#define VCXK_INIT_PIN(PORT, PIN, DDR, I0O1) \
|
||||
do { \
|
||||
writel(PIN, &pio->PORT.per); \
|
||||
writel(PIN, &pio->PORT.DDR); \
|
||||
writel(PIN, &pio->PORT.mddr); \
|
||||
if (!I0O1) \
|
||||
writel(PIN, &pio->PORT.puer); \
|
||||
} while (0);
|
||||
|
||||
#define VCXK_SET_PIN(PORT, PIN) writel(PIN, &pio->PORT.sodr);
|
||||
#define VCXK_CLR_PIN(PORT, PIN) writel(PIN, &pio->PORT.codr);
|
||||
|
||||
#define VCXK_ACKNOWLEDGE \
|
||||
(!(readl(&pio->CONFIG_SYS_VCXK_ACKNOWLEDGE_PORT.pdsr) & \
|
||||
CONFIG_SYS_VCXK_ACKNOWLEDGE_PIN))
|
||||
#else
|
||||
#define VCXK_INIT_PIN(PORT, PIN, DDR, I0O1) \
|
||||
((AT91PS_PIO) PORT)->PIO_PER = PIN; \
|
||||
((AT91PS_PIO) PORT)->DDR = PIN; \
|
||||
((AT91PS_PIO) PORT)->PIO_MDDR = PIN; \
|
||||
if (!I0O1) ((AT91PS_PIO) PORT)->PIO_PPUER = PIN;
|
||||
|
||||
#define VCXK_SET_PIN(PORT, PIN) ((AT91PS_PIO) PORT)->PIO_SODR = PIN;
|
||||
#define VCXK_CLR_PIN(PORT, PIN) ((AT91PS_PIO) PORT)->PIO_CODR = PIN;
|
||||
|
||||
#define VCXK_ACKNOWLEDGE \
|
||||
(!(((AT91PS_PIO) CONFIG_SYS_VCXK_ACKNOWLEDGE_PORT)->\
|
||||
PIO_PDSR & CONFIG_SYS_VCXK_ACKNOWLEDGE_PIN))
|
||||
#endif
|
||||
#elif defined(CONFIG_MCF52x2)
|
||||
#include <asm/m5282.h>
|
||||
#ifndef VCBITMASK
|
||||
#define VCBITMASK(bitno) (0x8000 >> (bitno % 16))
|
||||
#endif
|
||||
|
||||
#define VCXK_INIT_PIN(PORT, PIN, DDR, I0O1) \
|
||||
if (I0O1) DDR |= PIN; else DDR &= ~PIN;
|
||||
|
||||
#define VCXK_SET_PIN(PORT, PIN) PORT |= PIN;
|
||||
#define VCXK_CLR_PIN(PORT, PIN) PORT &= ~PIN;
|
||||
|
||||
#define VCXK_ACKNOWLEDGE \
|
||||
(!(CONFIG_SYS_VCXK_ACKNOWLEDGE_PORT & \
|
||||
CONFIG_SYS_VCXK_ACKNOWLEDGE_PIN))
|
||||
|
||||
#else
|
||||
#error no vcxk support for selected ARCH
|
||||
#endif
|
||||
|
||||
#define VCXK_DISABLE\
|
||||
VCXK_SET_PIN(CONFIG_SYS_VCXK_ENABLE_PORT, CONFIG_SYS_VCXK_ENABLE_PIN)
|
||||
#define VCXK_ENABLE\
|
||||
VCXK_CLR_PIN(CONFIG_SYS_VCXK_ENABLE_PORT, CONFIG_SYS_VCXK_ENABLE_PIN)
|
||||
|
||||
#ifndef CONFIG_SYS_VCXK_DOUBLEBUFFERED
|
||||
#define VCXK_BWS(x, data) vcxk_bws[x] = data;
|
||||
#define VCXK_BWS_WORD_SET(x, mask) vcxk_bws_word[x] |= mask;
|
||||
#define VCXK_BWS_WORD_CLEAR(x, mask) vcxk_bws_word[x] &= ~mask;
|
||||
#define VCXK_BWS_LONG(x, data) vcxk_bws_long[x] = data;
|
||||
#else
|
||||
u_char double_bws[16384];
|
||||
u_short *double_bws_word;
|
||||
u_long *double_bws_long;
|
||||
#define VCXK_BWS(x,data) \
|
||||
double_bws[x] = data; vcxk_bws[x] = data;
|
||||
#define VCXK_BWS_WORD_SET(x,mask) \
|
||||
double_bws_word[x] |= mask; \
|
||||
vcxk_bws_word[x] = double_bws_word[x];
|
||||
#define VCXK_BWS_WORD_CLEAR(x,mask) \
|
||||
double_bws_word[x] &= ~mask; \
|
||||
vcxk_bws_word[x] = double_bws_word[x];
|
||||
#define VCXK_BWS_LONG(x,data) \
|
||||
double_bws_long[x] = data; vcxk_bws_long[x] = data;
|
||||
#endif
|
||||
|
||||
#define VC4K16_Bright1 vcxk_bws_word[0x20004 / 2]
|
||||
#define VC4K16_Bright2 vcxk_bws_word[0x20006 / 2]
|
||||
#define VC2K_Bright vcxk_bws[0x8000]
|
||||
#define VC8K_BrightH vcxk_bws[0xC000]
|
||||
#define VC8K_BrightL vcxk_bws[0xC001]
|
||||
|
||||
vu_char VC4K16;
|
||||
|
||||
u_long display_width;
|
||||
u_long display_height;
|
||||
u_long display_bwidth;
|
||||
|
||||
ulong search_vcxk_driver(void);
|
||||
void vcxk_cls(void);
|
||||
void vcxk_setbrightness(unsigned int side, short brightness);
|
||||
int vcxk_request(void);
|
||||
int vcxk_acknowledge_wait(void);
|
||||
void vcxk_clear(void);
|
||||
|
||||
/*
|
||||
****f* bus_vcxk/vcxk_init
|
||||
* FUNCTION
|
||||
* initialalize Video Controller
|
||||
* PARAMETERS
|
||||
* width visible display width in pixel
|
||||
* height visible display height in pixel
|
||||
***
|
||||
*/
|
||||
|
||||
int vcxk_init(unsigned long width, unsigned long height)
|
||||
{
|
||||
#ifdef CONFIG_SYS_VCXK_RESET_PORT
|
||||
VCXK_INIT_PIN(CONFIG_SYS_VCXK_RESET_PORT,
|
||||
CONFIG_SYS_VCXK_RESET_PIN, CONFIG_SYS_VCXK_RESET_DDR, 1)
|
||||
VCXK_SET_PIN(CONFIG_SYS_VCXK_RESET_PORT, CONFIG_SYS_VCXK_RESET_PIN);
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_SYS_VCXK_DOUBLEBUFFERED
|
||||
double_bws_word = (u_short *)double_bws;
|
||||
double_bws_long = (u_long *)double_bws;
|
||||
debug("%lx %lx %lx \n", double_bws, double_bws_word, double_bws_long);
|
||||
#endif
|
||||
display_width = width;
|
||||
display_height = height;
|
||||
#if (CONFIG_SYS_VCXK_DEFAULT_LINEALIGN == 4)
|
||||
display_bwidth = ((width + 31) / 8) & ~0x3;
|
||||
#elif (CONFIG_SYS_VCXK_DEFAULT_LINEALIGN == 2)
|
||||
display_bwidth = ((width + 15) / 8) & ~0x1;
|
||||
#else
|
||||
#error CONFIG_SYS_VCXK_DEFAULT_LINEALIGN is invalid
|
||||
#endif
|
||||
debug("linesize ((%ld + 15) / 8 & ~0x1) = %ld\n",
|
||||
display_width, display_bwidth);
|
||||
|
||||
#ifdef CONFIG_SYS_VCXK_AUTODETECT
|
||||
VC4K16 = 0;
|
||||
vcxk_bws_long[1] = 0x0;
|
||||
vcxk_bws_long[1] = 0x55AAAA55;
|
||||
vcxk_bws_long[5] = 0x0;
|
||||
if (vcxk_bws_long[1] == 0x55AAAA55)
|
||||
VC4K16 = 1;
|
||||
#else
|
||||
VC4K16 = 1;
|
||||
debug("No autodetect: use vc4k\n");
|
||||
#endif
|
||||
|
||||
VCXK_INIT_PIN(CONFIG_SYS_VCXK_INVERT_PORT,
|
||||
CONFIG_SYS_VCXK_INVERT_PIN, CONFIG_SYS_VCXK_INVERT_DDR, 1)
|
||||
VCXK_SET_PIN(CONFIG_SYS_VCXK_INVERT_PORT, CONFIG_SYS_VCXK_INVERT_PIN)
|
||||
|
||||
VCXK_SET_PIN(CONFIG_SYS_VCXK_REQUEST_PORT, CONFIG_SYS_VCXK_REQUEST_PIN);
|
||||
VCXK_INIT_PIN(CONFIG_SYS_VCXK_REQUEST_PORT,
|
||||
CONFIG_SYS_VCXK_REQUEST_PIN, CONFIG_SYS_VCXK_REQUEST_DDR, 1)
|
||||
|
||||
VCXK_INIT_PIN(CONFIG_SYS_VCXK_ACKNOWLEDGE_PORT,
|
||||
CONFIG_SYS_VCXK_ACKNOWLEDGE_PIN,
|
||||
CONFIG_SYS_VCXK_ACKNOWLEDGE_DDR, 0)
|
||||
|
||||
VCXK_DISABLE;
|
||||
VCXK_INIT_PIN(CONFIG_SYS_VCXK_ENABLE_PORT,
|
||||
CONFIG_SYS_VCXK_ENABLE_PIN, CONFIG_SYS_VCXK_ENABLE_DDR, 1)
|
||||
|
||||
vcxk_cls();
|
||||
vcxk_cls(); /* clear second/hidden page */
|
||||
|
||||
vcxk_setbrightness(3, 1000);
|
||||
VCXK_ENABLE;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
****f* bus_vcxk/vcxk_setpixel
|
||||
* FUNCTION
|
||||
* set the pixel[x,y] with the given color
|
||||
* PARAMETER
|
||||
* x pixel colum
|
||||
* y pixel row
|
||||
* color <0x40 off/black
|
||||
* >0x40 on
|
||||
***
|
||||
*/
|
||||
|
||||
void vcxk_setpixel(int x, int y, unsigned long color)
|
||||
{
|
||||
vu_short dataptr;
|
||||
|
||||
if ((x < display_width) && (y < display_height)) {
|
||||
dataptr = ((x / 16)) + (y * (display_bwidth >> 1));
|
||||
|
||||
color = ((color >> 16) & 0xFF) |
|
||||
((color >> 8) & 0xFF) | (color & 0xFF);
|
||||
|
||||
if (color > 0x40) {
|
||||
VCXK_BWS_WORD_SET(dataptr, VCBITMASK(x));
|
||||
} else {
|
||||
VCXK_BWS_WORD_CLEAR(dataptr, VCBITMASK(x));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
****f* bus_vcxk/vcxk_loadimage
|
||||
* FUNCTION
|
||||
* copies a binary image to display memory
|
||||
***
|
||||
*/
|
||||
|
||||
void vcxk_loadimage(ulong source)
|
||||
{
|
||||
int cnt;
|
||||
vcxk_acknowledge_wait();
|
||||
if (VC4K16) {
|
||||
for (cnt = 0; cnt < (16384 / 4); cnt++) {
|
||||
VCXK_BWS_LONG(cnt, (*(ulong *) source));
|
||||
source = source + 4;
|
||||
}
|
||||
} else {
|
||||
for (cnt = 0; cnt < 16384; cnt++) {
|
||||
VCXK_BWS_LONG(cnt*2, (*(vu_char *) source));
|
||||
source++;
|
||||
}
|
||||
}
|
||||
vcxk_request();
|
||||
}
|
||||
|
||||
/*
|
||||
****f* bus_vcxk/vcxk_cls
|
||||
* FUNCTION
|
||||
* clear the display
|
||||
***
|
||||
*/
|
||||
|
||||
void vcxk_cls(void)
|
||||
{
|
||||
vcxk_acknowledge_wait();
|
||||
vcxk_clear();
|
||||
vcxk_request();
|
||||
}
|
||||
|
||||
/*
|
||||
****f* bus_vcxk/vcxk_clear(void)
|
||||
* FUNCTION
|
||||
* clear the display memory
|
||||
***
|
||||
*/
|
||||
|
||||
void vcxk_clear(void)
|
||||
{
|
||||
int cnt;
|
||||
|
||||
for (cnt = 0; cnt < (16384 / 4); cnt++) {
|
||||
VCXK_BWS_LONG(cnt, 0)
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
****f* bus_vcxk/vcxk_setbrightness
|
||||
* FUNCTION
|
||||
* set the display brightness
|
||||
* PARAMETER
|
||||
* side 1 set front side brightness
|
||||
* 2 set back side brightness
|
||||
* 3 set brightness for both sides
|
||||
* brightness 0..1000
|
||||
***
|
||||
*/
|
||||
|
||||
void vcxk_setbrightness(unsigned int side, short brightness)
|
||||
{
|
||||
if (VC4K16) {
|
||||
if ((side == 0) || (side & 0x1))
|
||||
VC4K16_Bright1 = brightness + 23;
|
||||
if ((side == 0) || (side & 0x2))
|
||||
VC4K16_Bright2 = brightness + 23;
|
||||
} else {
|
||||
VC2K_Bright = (brightness >> 4) + 2;
|
||||
VC8K_BrightH = (brightness + 23) >> 8;
|
||||
VC8K_BrightL = (brightness + 23) & 0xFF;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
****f* bus_vcxk/vcxk_request
|
||||
* FUNCTION
|
||||
* requests viewing of display memory
|
||||
***
|
||||
*/
|
||||
|
||||
int vcxk_request(void)
|
||||
{
|
||||
VCXK_CLR_PIN(CONFIG_SYS_VCXK_REQUEST_PORT,
|
||||
CONFIG_SYS_VCXK_REQUEST_PIN)
|
||||
VCXK_SET_PIN(CONFIG_SYS_VCXK_REQUEST_PORT,
|
||||
CONFIG_SYS_VCXK_REQUEST_PIN);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
****f* bus_vcxk/vcxk_acknowledge_wait
|
||||
* FUNCTION
|
||||
* wait for acknowledge viewing requests
|
||||
***
|
||||
*/
|
||||
|
||||
int vcxk_acknowledge_wait(void)
|
||||
{
|
||||
while (VCXK_ACKNOWLEDGE)
|
||||
;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
****f* bus_vcxk/vcxk_draw_mono
|
||||
* FUNCTION
|
||||
* copies a monochrom bitmap (BMP-Format) from given memory
|
||||
* PARAMETER
|
||||
* dataptr pointer to bitmap
|
||||
* x output bitmap @ columne
|
||||
* y output bitmap @ row
|
||||
***
|
||||
*/
|
||||
|
||||
void vcxk_draw_mono(unsigned char *dataptr, unsigned long linewidth,
|
||||
unsigned long cp_width, unsigned long cp_height)
|
||||
{
|
||||
unsigned char *lineptr;
|
||||
unsigned long xcnt, ycnt;
|
||||
|
||||
for (ycnt = cp_height; ycnt > 0; ycnt--) {
|
||||
lineptr = dataptr;
|
||||
for (xcnt = 0; xcnt < cp_width; xcnt++) {
|
||||
if ((*lineptr << (xcnt % 8)) & 0x80)
|
||||
vcxk_setpixel(xcnt, ycnt - 1, 0xFFFFFF);
|
||||
else
|
||||
vcxk_setpixel(xcnt, ycnt-1, 0);
|
||||
|
||||
if ((xcnt % 8) == 7)
|
||||
lineptr++;
|
||||
} /* endfor xcnt */
|
||||
dataptr = dataptr + linewidth;
|
||||
} /* endfor ycnt */
|
||||
}
|
||||
|
||||
/*
|
||||
****f* bus_vcxk/vcxk_display_bitmap
|
||||
* FUNCTION
|
||||
* copies a bitmap (BMP-Format) to the given position
|
||||
* PARAMETER
|
||||
* addr pointer to bitmap
|
||||
* x output bitmap @ columne
|
||||
* y output bitmap @ row
|
||||
***
|
||||
*/
|
||||
|
||||
int vcxk_display_bitmap(ulong addr, int x, int y)
|
||||
{
|
||||
bmp_image_t *bmp;
|
||||
unsigned long width;
|
||||
unsigned long height;
|
||||
unsigned long bpp;
|
||||
|
||||
unsigned long lw;
|
||||
|
||||
unsigned long c_width;
|
||||
unsigned long c_height;
|
||||
unsigned char *dataptr;
|
||||
|
||||
bmp = (bmp_image_t *) addr;
|
||||
if ((bmp->header.signature[0] == 'B') &&
|
||||
(bmp->header.signature[1] == 'M')) {
|
||||
width = le32_to_cpu(bmp->header.width);
|
||||
height = le32_to_cpu(bmp->header.height);
|
||||
bpp = le16_to_cpu(bmp->header.bit_count);
|
||||
|
||||
dataptr = (unsigned char *) bmp +
|
||||
le32_to_cpu(bmp->header.data_offset);
|
||||
|
||||
if (display_width < (width + x))
|
||||
c_width = display_width - x;
|
||||
else
|
||||
c_width = width;
|
||||
if (display_height < (height + y))
|
||||
c_height = display_height - y;
|
||||
else
|
||||
c_height = height;
|
||||
|
||||
lw = (((width + 7) / 8) + 3) & ~0x3;
|
||||
|
||||
if (c_height < height)
|
||||
dataptr = dataptr + lw * (height - c_height);
|
||||
switch (bpp) {
|
||||
case 1:
|
||||
vcxk_draw_mono(dataptr, lw, c_width, c_height);
|
||||
break;
|
||||
default:
|
||||
printf("Error: %ld bit per pixel "
|
||||
"not supported by VCxK\n", bpp);
|
||||
return 0;
|
||||
}
|
||||
} else {
|
||||
printf("Error: no valid bmp at %lx\n", (ulong) bmp);
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
****f* bus_vcxk/video_display_bitmap
|
||||
***
|
||||
*/
|
||||
|
||||
int video_display_bitmap(ulong addr, int x, int y)
|
||||
{
|
||||
vcxk_acknowledge_wait();
|
||||
if (vcxk_display_bitmap(addr, x, y)) {
|
||||
vcxk_request();
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* EOF */
|
||||
1867
common/package/boot/uboot-ipq40xx/src/drivers/video/cfb_console.c
Normal file
1867
common/package/boot/uboot-ipq40xx/src/drivers/video/cfb_console.c
Normal file
File diff suppressed because it is too large
Load diff
1283
common/package/boot/uboot-ipq40xx/src/drivers/video/ct69000.c
Normal file
1283
common/package/boot/uboot-ipq40xx/src/drivers/video/ct69000.c
Normal file
File diff suppressed because it is too large
Load diff
842
common/package/boot/uboot-ipq40xx/src/drivers/video/da8xx-fb.c
Normal file
842
common/package/boot/uboot-ipq40xx/src/drivers/video/da8xx-fb.c
Normal file
|
|
@ -0,0 +1,842 @@
|
|||
/*
|
||||
* Porting to u-boot:
|
||||
*
|
||||
* (C) Copyright 2011
|
||||
* Stefano Babic, DENX Software Engineering, sbabic@denx.de.
|
||||
*
|
||||
* Copyright (C) 2008-2009 MontaVista Software Inc.
|
||||
* Copyright (C) 2008-2009 Texas Instruments Inc
|
||||
*
|
||||
* Based on the LCD driver for TI Avalanche processors written by
|
||||
* Ajay Singh and Shalom Hai.
|
||||
*
|
||||
* 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 <common.h>
|
||||
#include <malloc.h>
|
||||
#include <video_fb.h>
|
||||
#include <linux/list.h>
|
||||
#include <linux/fb.h>
|
||||
|
||||
#include <asm/errno.h>
|
||||
#include <asm/io.h>
|
||||
#include <asm/arch/hardware.h>
|
||||
|
||||
#include "videomodes.h"
|
||||
#include <asm/arch/da8xx-fb.h>
|
||||
|
||||
#define DRIVER_NAME "da8xx_lcdc"
|
||||
|
||||
/* LCD Status Register */
|
||||
#define LCD_END_OF_FRAME1 (1 << 9)
|
||||
#define LCD_END_OF_FRAME0 (1 << 8)
|
||||
#define LCD_PL_LOAD_DONE (1 << 6)
|
||||
#define LCD_FIFO_UNDERFLOW (1 << 5)
|
||||
#define LCD_SYNC_LOST (1 << 2)
|
||||
|
||||
/* LCD DMA Control Register */
|
||||
#define LCD_DMA_BURST_SIZE(x) ((x) << 4)
|
||||
#define LCD_DMA_BURST_1 0x0
|
||||
#define LCD_DMA_BURST_2 0x1
|
||||
#define LCD_DMA_BURST_4 0x2
|
||||
#define LCD_DMA_BURST_8 0x3
|
||||
#define LCD_DMA_BURST_16 0x4
|
||||
#define LCD_END_OF_FRAME_INT_ENA (1 << 2)
|
||||
#define LCD_DUAL_FRAME_BUFFER_ENABLE (1 << 0)
|
||||
|
||||
/* LCD Control Register */
|
||||
#define LCD_CLK_DIVISOR(x) ((x) << 8)
|
||||
#define LCD_RASTER_MODE 0x01
|
||||
|
||||
/* LCD Raster Control Register */
|
||||
#define LCD_PALETTE_LOAD_MODE(x) ((x) << 20)
|
||||
#define PALETTE_AND_DATA 0x00
|
||||
#define PALETTE_ONLY 0x01
|
||||
#define DATA_ONLY 0x02
|
||||
|
||||
#define LCD_MONO_8BIT_MODE (1 << 9)
|
||||
#define LCD_RASTER_ORDER (1 << 8)
|
||||
#define LCD_TFT_MODE (1 << 7)
|
||||
#define LCD_UNDERFLOW_INT_ENA (1 << 6)
|
||||
#define LCD_PL_ENABLE (1 << 4)
|
||||
#define LCD_MONOCHROME_MODE (1 << 1)
|
||||
#define LCD_RASTER_ENABLE (1 << 0)
|
||||
#define LCD_TFT_ALT_ENABLE (1 << 23)
|
||||
#define LCD_STN_565_ENABLE (1 << 24)
|
||||
|
||||
/* LCD Raster Timing 2 Register */
|
||||
#define LCD_AC_BIAS_TRANSITIONS_PER_INT(x) ((x) << 16)
|
||||
#define LCD_AC_BIAS_FREQUENCY(x) ((x) << 8)
|
||||
#define LCD_SYNC_CTRL (1 << 25)
|
||||
#define LCD_SYNC_EDGE (1 << 24)
|
||||
#define LCD_INVERT_PIXEL_CLOCK (1 << 22)
|
||||
#define LCD_INVERT_LINE_CLOCK (1 << 21)
|
||||
#define LCD_INVERT_FRAME_CLOCK (1 << 20)
|
||||
|
||||
/* LCD Block */
|
||||
struct da8xx_lcd_regs {
|
||||
u32 revid;
|
||||
u32 ctrl;
|
||||
u32 stat;
|
||||
u32 lidd_ctrl;
|
||||
u32 lidd_cs0_conf;
|
||||
u32 lidd_cs0_addr;
|
||||
u32 lidd_cs0_data;
|
||||
u32 lidd_cs1_conf;
|
||||
u32 lidd_cs1_addr;
|
||||
u32 lidd_cs1_data;
|
||||
u32 raster_ctrl;
|
||||
u32 raster_timing_0;
|
||||
u32 raster_timing_1;
|
||||
u32 raster_timing_2;
|
||||
u32 raster_subpanel;
|
||||
u32 reserved;
|
||||
u32 dma_ctrl;
|
||||
u32 dma_frm_buf_base_addr_0;
|
||||
u32 dma_frm_buf_ceiling_addr_0;
|
||||
u32 dma_frm_buf_base_addr_1;
|
||||
u32 dma_frm_buf_ceiling_addr_1;
|
||||
};
|
||||
|
||||
#define LCD_NUM_BUFFERS 1
|
||||
|
||||
#define WSI_TIMEOUT 50
|
||||
#define PALETTE_SIZE 256
|
||||
#define LEFT_MARGIN 64
|
||||
#define RIGHT_MARGIN 64
|
||||
#define UPPER_MARGIN 32
|
||||
#define LOWER_MARGIN 32
|
||||
|
||||
#define calc_fbsize() (panel.plnSizeX * panel.plnSizeY * panel.gdfBytesPP)
|
||||
|
||||
static struct da8xx_lcd_regs *da8xx_fb_reg_base;
|
||||
|
||||
DECLARE_GLOBAL_DATA_PTR;
|
||||
|
||||
/* graphics setup */
|
||||
static GraphicDevice gpanel;
|
||||
static const struct da8xx_panel *lcd_panel;
|
||||
static struct fb_info *da8xx_fb_info;
|
||||
static int bits_x_pixel;
|
||||
|
||||
static inline unsigned int lcdc_read(u32 *addr)
|
||||
{
|
||||
return (unsigned int)readl(addr);
|
||||
}
|
||||
|
||||
static inline void lcdc_write(unsigned int val, u32 *addr)
|
||||
{
|
||||
writel(val, addr);
|
||||
}
|
||||
|
||||
struct da8xx_fb_par {
|
||||
u32 p_palette_base;
|
||||
unsigned char *v_palette_base;
|
||||
dma_addr_t vram_phys;
|
||||
unsigned long vram_size;
|
||||
void *vram_virt;
|
||||
unsigned int dma_start;
|
||||
unsigned int dma_end;
|
||||
struct clk *lcdc_clk;
|
||||
int irq;
|
||||
unsigned short pseudo_palette[16];
|
||||
unsigned int palette_sz;
|
||||
unsigned int pxl_clk;
|
||||
int blank;
|
||||
int vsync_flag;
|
||||
int vsync_timeout;
|
||||
};
|
||||
|
||||
|
||||
/* Variable Screen Information */
|
||||
static struct fb_var_screeninfo da8xx_fb_var = {
|
||||
.xoffset = 0,
|
||||
.yoffset = 0,
|
||||
.transp = {0, 0, 0},
|
||||
.nonstd = 0,
|
||||
.activate = 0,
|
||||
.height = -1,
|
||||
.width = -1,
|
||||
.pixclock = 46666, /* 46us - AUO display */
|
||||
.accel_flags = 0,
|
||||
.left_margin = LEFT_MARGIN,
|
||||
.right_margin = RIGHT_MARGIN,
|
||||
.upper_margin = UPPER_MARGIN,
|
||||
.lower_margin = LOWER_MARGIN,
|
||||
.sync = 0,
|
||||
.vmode = FB_VMODE_NONINTERLACED
|
||||
};
|
||||
|
||||
static struct fb_fix_screeninfo da8xx_fb_fix = {
|
||||
.id = "DA8xx FB Drv",
|
||||
.type = FB_TYPE_PACKED_PIXELS,
|
||||
.type_aux = 0,
|
||||
.visual = FB_VISUAL_PSEUDOCOLOR,
|
||||
.xpanstep = 0,
|
||||
.ypanstep = 1,
|
||||
.ywrapstep = 0,
|
||||
.accel = FB_ACCEL_NONE
|
||||
};
|
||||
|
||||
static const struct display_panel disp_panel = {
|
||||
QVGA,
|
||||
16,
|
||||
16,
|
||||
COLOR_ACTIVE,
|
||||
};
|
||||
|
||||
static const struct lcd_ctrl_config lcd_cfg = {
|
||||
&disp_panel,
|
||||
.ac_bias = 255,
|
||||
.ac_bias_intrpt = 0,
|
||||
.dma_burst_sz = 16,
|
||||
.bpp = 16,
|
||||
.fdd = 255,
|
||||
.tft_alt_mode = 0,
|
||||
.stn_565_mode = 0,
|
||||
.mono_8bit_mode = 0,
|
||||
.invert_line_clock = 1,
|
||||
.invert_frm_clock = 1,
|
||||
.sync_edge = 0,
|
||||
.sync_ctrl = 1,
|
||||
.raster_order = 0,
|
||||
};
|
||||
|
||||
/* Enable the Raster Engine of the LCD Controller */
|
||||
static inline void lcd_enable_raster(void)
|
||||
{
|
||||
u32 reg;
|
||||
|
||||
reg = lcdc_read(&da8xx_fb_reg_base->raster_ctrl);
|
||||
if (!(reg & LCD_RASTER_ENABLE))
|
||||
lcdc_write(reg | LCD_RASTER_ENABLE,
|
||||
&da8xx_fb_reg_base->raster_ctrl);
|
||||
}
|
||||
|
||||
/* Disable the Raster Engine of the LCD Controller */
|
||||
static inline void lcd_disable_raster(void)
|
||||
{
|
||||
u32 reg;
|
||||
|
||||
reg = lcdc_read(&da8xx_fb_reg_base->raster_ctrl);
|
||||
if (reg & LCD_RASTER_ENABLE)
|
||||
lcdc_write(reg & ~LCD_RASTER_ENABLE,
|
||||
&da8xx_fb_reg_base->raster_ctrl);
|
||||
}
|
||||
|
||||
static void lcd_blit(int load_mode, struct da8xx_fb_par *par)
|
||||
{
|
||||
u32 start;
|
||||
u32 end;
|
||||
u32 reg_ras;
|
||||
u32 reg_dma;
|
||||
|
||||
/* init reg to clear PLM (loading mode) fields */
|
||||
reg_ras = lcdc_read(&da8xx_fb_reg_base->raster_ctrl);
|
||||
reg_ras &= ~(3 << 20);
|
||||
|
||||
reg_dma = lcdc_read(&da8xx_fb_reg_base->dma_ctrl);
|
||||
|
||||
if (load_mode == LOAD_DATA) {
|
||||
start = par->dma_start;
|
||||
end = par->dma_end;
|
||||
|
||||
reg_ras |= LCD_PALETTE_LOAD_MODE(DATA_ONLY);
|
||||
reg_dma |= LCD_END_OF_FRAME_INT_ENA;
|
||||
|
||||
#if (LCD_NUM_BUFFERS == 2)
|
||||
reg_dma |= LCD_DUAL_FRAME_BUFFER_ENABLE;
|
||||
lcdc_write(start, &da8xx_fb_reg_base->dma_frm_buf_base_addr_0);
|
||||
lcdc_write(end, &da8xx_fb_reg_base->dma_frm_buf_ceiling_addr_0);
|
||||
lcdc_write(start, &da8xx_fb_reg_base->dma_frm_buf_base_addr_1);
|
||||
lcdc_write(end, &da8xx_fb_reg_base->dma_frm_buf_ceiling_addr_1);
|
||||
#else
|
||||
reg_dma &= ~LCD_DUAL_FRAME_BUFFER_ENABLE;
|
||||
lcdc_write(start, &da8xx_fb_reg_base->dma_frm_buf_base_addr_0);
|
||||
lcdc_write(end, &da8xx_fb_reg_base->dma_frm_buf_ceiling_addr_0);
|
||||
lcdc_write(0, &da8xx_fb_reg_base->dma_frm_buf_base_addr_1);
|
||||
lcdc_write(0, &da8xx_fb_reg_base->dma_frm_buf_ceiling_addr_1);
|
||||
#endif
|
||||
|
||||
} else if (load_mode == LOAD_PALETTE) {
|
||||
start = par->p_palette_base;
|
||||
end = start + par->palette_sz - 1;
|
||||
|
||||
reg_ras |= LCD_PALETTE_LOAD_MODE(PALETTE_ONLY);
|
||||
reg_ras |= LCD_PL_ENABLE;
|
||||
|
||||
lcdc_write(start, &da8xx_fb_reg_base->dma_frm_buf_base_addr_0);
|
||||
lcdc_write(end, &da8xx_fb_reg_base->dma_frm_buf_ceiling_addr_0);
|
||||
}
|
||||
|
||||
lcdc_write(reg_dma, &da8xx_fb_reg_base->dma_ctrl);
|
||||
lcdc_write(reg_ras, &da8xx_fb_reg_base->raster_ctrl);
|
||||
|
||||
/*
|
||||
* The Raster enable bit must be set after all other control fields are
|
||||
* set.
|
||||
*/
|
||||
lcd_enable_raster();
|
||||
}
|
||||
|
||||
/* Configure the Burst Size of DMA */
|
||||
static int lcd_cfg_dma(int burst_size)
|
||||
{
|
||||
u32 reg;
|
||||
|
||||
reg = lcdc_read(&da8xx_fb_reg_base->dma_ctrl) & 0x00000001;
|
||||
switch (burst_size) {
|
||||
case 1:
|
||||
reg |= LCD_DMA_BURST_SIZE(LCD_DMA_BURST_1);
|
||||
break;
|
||||
case 2:
|
||||
reg |= LCD_DMA_BURST_SIZE(LCD_DMA_BURST_2);
|
||||
break;
|
||||
case 4:
|
||||
reg |= LCD_DMA_BURST_SIZE(LCD_DMA_BURST_4);
|
||||
break;
|
||||
case 8:
|
||||
reg |= LCD_DMA_BURST_SIZE(LCD_DMA_BURST_8);
|
||||
break;
|
||||
case 16:
|
||||
reg |= LCD_DMA_BURST_SIZE(LCD_DMA_BURST_16);
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
lcdc_write(reg, &da8xx_fb_reg_base->dma_ctrl);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void lcd_cfg_ac_bias(int period, int transitions_per_int)
|
||||
{
|
||||
u32 reg;
|
||||
|
||||
/* Set the AC Bias Period and Number of Transisitons per Interrupt */
|
||||
reg = lcdc_read(&da8xx_fb_reg_base->raster_timing_2) & 0xFFF00000;
|
||||
reg |= LCD_AC_BIAS_FREQUENCY(period) |
|
||||
LCD_AC_BIAS_TRANSITIONS_PER_INT(transitions_per_int);
|
||||
lcdc_write(reg, &da8xx_fb_reg_base->raster_timing_2);
|
||||
}
|
||||
|
||||
static void lcd_cfg_horizontal_sync(int back_porch, int pulse_width,
|
||||
int front_porch)
|
||||
{
|
||||
u32 reg;
|
||||
|
||||
reg = lcdc_read(&da8xx_fb_reg_base->raster_timing_0) & 0xf;
|
||||
reg |= ((back_porch & 0xff) << 24)
|
||||
| ((front_porch & 0xff) << 16)
|
||||
| ((pulse_width & 0x3f) << 10);
|
||||
lcdc_write(reg, &da8xx_fb_reg_base->raster_timing_0);
|
||||
}
|
||||
|
||||
static void lcd_cfg_vertical_sync(int back_porch, int pulse_width,
|
||||
int front_porch)
|
||||
{
|
||||
u32 reg;
|
||||
|
||||
reg = lcdc_read(&da8xx_fb_reg_base->raster_timing_1) & 0x3ff;
|
||||
reg |= ((back_porch & 0xff) << 24)
|
||||
| ((front_porch & 0xff) << 16)
|
||||
| ((pulse_width & 0x3f) << 10);
|
||||
lcdc_write(reg, &da8xx_fb_reg_base->raster_timing_1);
|
||||
}
|
||||
|
||||
static int lcd_cfg_display(const struct lcd_ctrl_config *cfg)
|
||||
{
|
||||
u32 reg;
|
||||
|
||||
reg = lcdc_read(&da8xx_fb_reg_base->raster_ctrl) & ~(LCD_TFT_MODE |
|
||||
LCD_MONO_8BIT_MODE |
|
||||
LCD_MONOCHROME_MODE);
|
||||
|
||||
switch (cfg->p_disp_panel->panel_shade) {
|
||||
case MONOCHROME:
|
||||
reg |= LCD_MONOCHROME_MODE;
|
||||
if (cfg->mono_8bit_mode)
|
||||
reg |= LCD_MONO_8BIT_MODE;
|
||||
break;
|
||||
case COLOR_ACTIVE:
|
||||
reg |= LCD_TFT_MODE;
|
||||
if (cfg->tft_alt_mode)
|
||||
reg |= LCD_TFT_ALT_ENABLE;
|
||||
break;
|
||||
|
||||
case COLOR_PASSIVE:
|
||||
if (cfg->stn_565_mode)
|
||||
reg |= LCD_STN_565_ENABLE;
|
||||
break;
|
||||
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* enable additional interrupts here */
|
||||
reg |= LCD_UNDERFLOW_INT_ENA;
|
||||
|
||||
lcdc_write(reg, &da8xx_fb_reg_base->raster_ctrl);
|
||||
|
||||
reg = lcdc_read(&da8xx_fb_reg_base->raster_timing_2);
|
||||
|
||||
if (cfg->sync_ctrl)
|
||||
reg |= LCD_SYNC_CTRL;
|
||||
else
|
||||
reg &= ~LCD_SYNC_CTRL;
|
||||
|
||||
if (cfg->sync_edge)
|
||||
reg |= LCD_SYNC_EDGE;
|
||||
else
|
||||
reg &= ~LCD_SYNC_EDGE;
|
||||
|
||||
if (cfg->invert_line_clock)
|
||||
reg |= LCD_INVERT_LINE_CLOCK;
|
||||
else
|
||||
reg &= ~LCD_INVERT_LINE_CLOCK;
|
||||
|
||||
if (cfg->invert_frm_clock)
|
||||
reg |= LCD_INVERT_FRAME_CLOCK;
|
||||
else
|
||||
reg &= ~LCD_INVERT_FRAME_CLOCK;
|
||||
|
||||
lcdc_write(reg, &da8xx_fb_reg_base->raster_timing_2);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int lcd_cfg_frame_buffer(struct da8xx_fb_par *par, u32 width, u32 height,
|
||||
u32 bpp, u32 raster_order)
|
||||
{
|
||||
u32 reg;
|
||||
|
||||
/* Set the Panel Width */
|
||||
/* Pixels per line = (PPL + 1)*16 */
|
||||
/*0x3F in bits 4..9 gives max horisontal resolution = 1024 pixels*/
|
||||
width &= 0x3f0;
|
||||
reg = lcdc_read(&da8xx_fb_reg_base->raster_timing_0);
|
||||
reg &= 0xfffffc00;
|
||||
reg |= ((width >> 4) - 1) << 4;
|
||||
lcdc_write(reg, &da8xx_fb_reg_base->raster_timing_0);
|
||||
|
||||
/* Set the Panel Height */
|
||||
reg = lcdc_read(&da8xx_fb_reg_base->raster_timing_1);
|
||||
reg = ((height - 1) & 0x3ff) | (reg & 0xfffffc00);
|
||||
lcdc_write(reg, &da8xx_fb_reg_base->raster_timing_1);
|
||||
|
||||
/* Set the Raster Order of the Frame Buffer */
|
||||
reg = lcdc_read(&da8xx_fb_reg_base->raster_ctrl) & ~(1 << 8);
|
||||
if (raster_order)
|
||||
reg |= LCD_RASTER_ORDER;
|
||||
lcdc_write(reg, &da8xx_fb_reg_base->raster_ctrl);
|
||||
|
||||
switch (bpp) {
|
||||
case 1:
|
||||
case 2:
|
||||
case 4:
|
||||
case 16:
|
||||
par->palette_sz = 16 * 2;
|
||||
break;
|
||||
|
||||
case 8:
|
||||
par->palette_sz = 256 * 2;
|
||||
break;
|
||||
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int fb_setcolreg(unsigned regno, unsigned red, unsigned green,
|
||||
unsigned blue, unsigned transp,
|
||||
struct fb_info *info)
|
||||
{
|
||||
struct da8xx_fb_par *par = info->par;
|
||||
unsigned short *palette = (unsigned short *) par->v_palette_base;
|
||||
u_short pal;
|
||||
int update_hw = 0;
|
||||
|
||||
if (regno > 255)
|
||||
return 1;
|
||||
|
||||
if (info->fix.visual == FB_VISUAL_DIRECTCOLOR)
|
||||
return 1;
|
||||
|
||||
if (info->var.bits_per_pixel == 8) {
|
||||
red >>= 4;
|
||||
green >>= 8;
|
||||
blue >>= 12;
|
||||
|
||||
pal = (red & 0x0f00);
|
||||
pal |= (green & 0x00f0);
|
||||
pal |= (blue & 0x000f);
|
||||
|
||||
if (palette[regno] != pal) {
|
||||
update_hw = 1;
|
||||
palette[regno] = pal;
|
||||
}
|
||||
} else if ((info->var.bits_per_pixel == 16) && regno < 16) {
|
||||
red >>= (16 - info->var.red.length);
|
||||
red <<= info->var.red.offset;
|
||||
|
||||
green >>= (16 - info->var.green.length);
|
||||
green <<= info->var.green.offset;
|
||||
|
||||
blue >>= (16 - info->var.blue.length);
|
||||
blue <<= info->var.blue.offset;
|
||||
|
||||
par->pseudo_palette[regno] = red | green | blue;
|
||||
|
||||
if (palette[0] != 0x4000) {
|
||||
update_hw = 1;
|
||||
palette[0] = 0x4000;
|
||||
}
|
||||
}
|
||||
|
||||
/* Update the palette in the h/w as needed. */
|
||||
if (update_hw)
|
||||
lcd_blit(LOAD_PALETTE, par);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void lcd_reset(struct da8xx_fb_par *par)
|
||||
{
|
||||
/* Disable the Raster if previously Enabled */
|
||||
lcd_disable_raster();
|
||||
|
||||
/* DMA has to be disabled */
|
||||
lcdc_write(0, &da8xx_fb_reg_base->dma_ctrl);
|
||||
lcdc_write(0, &da8xx_fb_reg_base->raster_ctrl);
|
||||
}
|
||||
|
||||
static void lcd_calc_clk_divider(struct da8xx_fb_par *par)
|
||||
{
|
||||
unsigned int lcd_clk, div;
|
||||
|
||||
/* Get clock from sysclk2 */
|
||||
lcd_clk = clk_get(2);
|
||||
|
||||
div = lcd_clk / par->pxl_clk;
|
||||
debug("LCD Clock: 0x%x Divider: 0x%x PixClk: 0x%x\n",
|
||||
lcd_clk, div, par->pxl_clk);
|
||||
|
||||
/* Configure the LCD clock divisor. */
|
||||
lcdc_write(LCD_CLK_DIVISOR(div) |
|
||||
(LCD_RASTER_MODE & 0x1), &da8xx_fb_reg_base->ctrl);
|
||||
}
|
||||
|
||||
static int lcd_init(struct da8xx_fb_par *par, const struct lcd_ctrl_config *cfg,
|
||||
const struct da8xx_panel *panel)
|
||||
{
|
||||
u32 bpp;
|
||||
int ret = 0;
|
||||
|
||||
lcd_reset(par);
|
||||
|
||||
/* Calculate the divider */
|
||||
lcd_calc_clk_divider(par);
|
||||
|
||||
if (panel->invert_pxl_clk)
|
||||
lcdc_write((lcdc_read(&da8xx_fb_reg_base->raster_timing_2) |
|
||||
LCD_INVERT_PIXEL_CLOCK),
|
||||
&da8xx_fb_reg_base->raster_timing_2);
|
||||
else
|
||||
lcdc_write((lcdc_read(&da8xx_fb_reg_base->raster_timing_2) &
|
||||
~LCD_INVERT_PIXEL_CLOCK),
|
||||
&da8xx_fb_reg_base->raster_timing_2);
|
||||
|
||||
/* Configure the DMA burst size. */
|
||||
ret = lcd_cfg_dma(cfg->dma_burst_sz);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
/* Configure the AC bias properties. */
|
||||
lcd_cfg_ac_bias(cfg->ac_bias, cfg->ac_bias_intrpt);
|
||||
|
||||
/* Configure the vertical and horizontal sync properties. */
|
||||
lcd_cfg_vertical_sync(panel->vbp, panel->vsw, panel->vfp);
|
||||
lcd_cfg_horizontal_sync(panel->hbp, panel->hsw, panel->hfp);
|
||||
|
||||
/* Configure for disply */
|
||||
ret = lcd_cfg_display(cfg);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
if (QVGA != cfg->p_disp_panel->panel_type)
|
||||
return -EINVAL;
|
||||
|
||||
if (cfg->bpp <= cfg->p_disp_panel->max_bpp &&
|
||||
cfg->bpp >= cfg->p_disp_panel->min_bpp)
|
||||
bpp = cfg->bpp;
|
||||
else
|
||||
bpp = cfg->p_disp_panel->max_bpp;
|
||||
if (bpp == 12)
|
||||
bpp = 16;
|
||||
ret = lcd_cfg_frame_buffer(par, (unsigned int)panel->width,
|
||||
(unsigned int)panel->height, bpp,
|
||||
cfg->raster_order);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
/* Configure FDD */
|
||||
lcdc_write((lcdc_read(&da8xx_fb_reg_base->raster_ctrl) & 0xfff00fff) |
|
||||
(cfg->fdd << 12), &da8xx_fb_reg_base->raster_ctrl);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void lcdc_dma_start(void)
|
||||
{
|
||||
struct da8xx_fb_par *par = da8xx_fb_info->par;
|
||||
lcdc_write(par->dma_start,
|
||||
&da8xx_fb_reg_base->dma_frm_buf_base_addr_0);
|
||||
lcdc_write(par->dma_end,
|
||||
&da8xx_fb_reg_base->dma_frm_buf_ceiling_addr_0);
|
||||
lcdc_write(0,
|
||||
&da8xx_fb_reg_base->dma_frm_buf_base_addr_1);
|
||||
lcdc_write(0,
|
||||
&da8xx_fb_reg_base->dma_frm_buf_ceiling_addr_1);
|
||||
}
|
||||
|
||||
static u32 lcdc_irq_handler(void)
|
||||
{
|
||||
struct da8xx_fb_par *par = da8xx_fb_info->par;
|
||||
u32 stat = lcdc_read(&da8xx_fb_reg_base->stat);
|
||||
u32 reg_ras;
|
||||
|
||||
if ((stat & LCD_SYNC_LOST) && (stat & LCD_FIFO_UNDERFLOW)) {
|
||||
debug("LCD_SYNC_LOST\n");
|
||||
lcd_disable_raster();
|
||||
lcdc_write(stat, &da8xx_fb_reg_base->stat);
|
||||
lcd_enable_raster();
|
||||
return LCD_SYNC_LOST;
|
||||
} else if (stat & LCD_PL_LOAD_DONE) {
|
||||
debug("LCD_PL_LOAD_DONE\n");
|
||||
/*
|
||||
* Must disable raster before changing state of any control bit.
|
||||
* And also must be disabled before clearing the PL loading
|
||||
* interrupt via the following write to the status register. If
|
||||
* this is done after then one gets multiple PL done interrupts.
|
||||
*/
|
||||
lcd_disable_raster();
|
||||
|
||||
lcdc_write(stat, &da8xx_fb_reg_base->stat);
|
||||
|
||||
/* Disable PL completion inerrupt */
|
||||
reg_ras = lcdc_read(&da8xx_fb_reg_base->raster_ctrl);
|
||||
reg_ras &= ~LCD_PL_ENABLE;
|
||||
lcdc_write(reg_ras, &da8xx_fb_reg_base->raster_ctrl);
|
||||
|
||||
/* Setup and start data loading mode */
|
||||
lcd_blit(LOAD_DATA, par);
|
||||
return LCD_PL_LOAD_DONE;
|
||||
} else {
|
||||
lcdc_write(stat, &da8xx_fb_reg_base->stat);
|
||||
|
||||
if (stat & LCD_END_OF_FRAME0)
|
||||
debug("LCD_END_OF_FRAME0\n");
|
||||
|
||||
lcdc_write(par->dma_start,
|
||||
&da8xx_fb_reg_base->dma_frm_buf_base_addr_0);
|
||||
lcdc_write(par->dma_end,
|
||||
&da8xx_fb_reg_base->dma_frm_buf_ceiling_addr_0);
|
||||
par->vsync_flag = 1;
|
||||
return LCD_END_OF_FRAME0;
|
||||
}
|
||||
return stat;
|
||||
}
|
||||
|
||||
static u32 wait_for_event(u32 event)
|
||||
{
|
||||
u32 timeout = 50000;
|
||||
u32 ret;
|
||||
|
||||
do {
|
||||
ret = lcdc_irq_handler();
|
||||
udelay(1000);
|
||||
} while (!(ret & event));
|
||||
|
||||
if (timeout <= 0) {
|
||||
printf("%s: event %d not hit\n", __func__, event);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
void *video_hw_init(void)
|
||||
{
|
||||
struct da8xx_fb_par *par;
|
||||
u32 size;
|
||||
char *p;
|
||||
|
||||
if (!lcd_panel) {
|
||||
printf("Display not initialized\n");
|
||||
return NULL;
|
||||
}
|
||||
gpanel.winSizeX = lcd_panel->width;
|
||||
gpanel.winSizeY = lcd_panel->height;
|
||||
gpanel.plnSizeX = lcd_panel->width;
|
||||
gpanel.plnSizeY = lcd_panel->height;
|
||||
|
||||
switch (bits_x_pixel) {
|
||||
case 24:
|
||||
gpanel.gdfBytesPP = 4;
|
||||
gpanel.gdfIndex = GDF_32BIT_X888RGB;
|
||||
break;
|
||||
case 16:
|
||||
gpanel.gdfBytesPP = 2;
|
||||
gpanel.gdfIndex = GDF_16BIT_565RGB;
|
||||
break;
|
||||
default:
|
||||
gpanel.gdfBytesPP = 1;
|
||||
gpanel.gdfIndex = GDF__8BIT_INDEX;
|
||||
break;
|
||||
}
|
||||
|
||||
da8xx_fb_reg_base = (struct da8xx_lcd_regs *)DAVINCI_LCD_CNTL_BASE;
|
||||
|
||||
debug("Resolution: %dx%d %x\n",
|
||||
gpanel.winSizeX,
|
||||
gpanel.winSizeY,
|
||||
lcd_cfg.bpp);
|
||||
|
||||
size = sizeof(struct fb_info) + sizeof(struct da8xx_fb_par);
|
||||
da8xx_fb_info = malloc(size);
|
||||
debug("da8xx_fb_info at %x\n", (unsigned int)da8xx_fb_info);
|
||||
|
||||
if (!da8xx_fb_info) {
|
||||
printf("Memory allocation failed for fb_info\n");
|
||||
return NULL;
|
||||
}
|
||||
memset(da8xx_fb_info, 0, size);
|
||||
p = (char *)da8xx_fb_info;
|
||||
da8xx_fb_info->par = p + sizeof(struct fb_info);
|
||||
debug("da8xx_par at %x\n", (unsigned int)da8xx_fb_info->par);
|
||||
|
||||
par = da8xx_fb_info->par;
|
||||
par->pxl_clk = lcd_panel->pxl_clk;
|
||||
|
||||
if (lcd_init(par, &lcd_cfg, lcd_panel) < 0) {
|
||||
printf("lcd_init failed\n");
|
||||
goto err_release_fb;
|
||||
}
|
||||
|
||||
/* allocate frame buffer */
|
||||
par->vram_size = lcd_panel->width * lcd_panel->height * lcd_cfg.bpp;
|
||||
par->vram_size = par->vram_size * LCD_NUM_BUFFERS / 8;
|
||||
|
||||
par->vram_virt = malloc(par->vram_size);
|
||||
|
||||
par->vram_phys = (dma_addr_t) par->vram_virt;
|
||||
debug("Requesting 0x%x bytes for framebuffer at 0x%x\n",
|
||||
(unsigned int)par->vram_size,
|
||||
(unsigned int)par->vram_virt);
|
||||
if (!par->vram_virt) {
|
||||
printf("GLCD: malloc for frame buffer failed\n");
|
||||
goto err_release_fb;
|
||||
}
|
||||
|
||||
gpanel.frameAdrs = (unsigned int)par->vram_virt;
|
||||
da8xx_fb_info->screen_base = (char *) par->vram_virt;
|
||||
da8xx_fb_fix.smem_start = gpanel.frameAdrs;
|
||||
da8xx_fb_fix.smem_len = par->vram_size;
|
||||
da8xx_fb_fix.line_length = (lcd_panel->width * lcd_cfg.bpp) / 8;
|
||||
|
||||
par->dma_start = par->vram_phys;
|
||||
par->dma_end = par->dma_start + lcd_panel->height *
|
||||
da8xx_fb_fix.line_length - 1;
|
||||
|
||||
/* allocate palette buffer */
|
||||
par->v_palette_base = malloc(PALETTE_SIZE);
|
||||
if (!par->v_palette_base) {
|
||||
printf("GLCD: malloc for palette buffer failed\n");
|
||||
goto err_release_fb_mem;
|
||||
}
|
||||
memset(par->v_palette_base, 0, PALETTE_SIZE);
|
||||
par->p_palette_base = (unsigned int)par->v_palette_base;
|
||||
|
||||
/* Initialize par */
|
||||
da8xx_fb_info->var.bits_per_pixel = lcd_cfg.bpp;
|
||||
|
||||
da8xx_fb_var.xres = lcd_panel->width;
|
||||
da8xx_fb_var.xres_virtual = lcd_panel->width;
|
||||
|
||||
da8xx_fb_var.yres = lcd_panel->height;
|
||||
da8xx_fb_var.yres_virtual = lcd_panel->height * LCD_NUM_BUFFERS;
|
||||
|
||||
da8xx_fb_var.grayscale =
|
||||
lcd_cfg.p_disp_panel->panel_shade == MONOCHROME ? 1 : 0;
|
||||
da8xx_fb_var.bits_per_pixel = lcd_cfg.bpp;
|
||||
|
||||
da8xx_fb_var.hsync_len = lcd_panel->hsw;
|
||||
da8xx_fb_var.vsync_len = lcd_panel->vsw;
|
||||
|
||||
/* Initialize fbinfo */
|
||||
da8xx_fb_info->flags = FBINFO_FLAG_DEFAULT;
|
||||
da8xx_fb_info->fix = da8xx_fb_fix;
|
||||
da8xx_fb_info->var = da8xx_fb_var;
|
||||
da8xx_fb_info->pseudo_palette = par->pseudo_palette;
|
||||
da8xx_fb_info->fix.visual = (da8xx_fb_info->var.bits_per_pixel <= 8) ?
|
||||
FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_TRUECOLOR;
|
||||
|
||||
/* Clear interrupt */
|
||||
memset((void *)par->vram_virt, 0, par->vram_size);
|
||||
lcd_disable_raster();
|
||||
lcdc_write(0xFFFF, &da8xx_fb_reg_base->stat);
|
||||
debug("Palette at 0x%x size %d\n", par->p_palette_base,
|
||||
par->palette_sz);
|
||||
lcdc_dma_start();
|
||||
|
||||
/* Load a default palette */
|
||||
fb_setcolreg(0, 0, 0, 0, 0xffff, da8xx_fb_info);
|
||||
|
||||
/* Check that the palette is loaded */
|
||||
wait_for_event(LCD_PL_LOAD_DONE);
|
||||
|
||||
/* Wait until DMA is working */
|
||||
wait_for_event(LCD_END_OF_FRAME0);
|
||||
|
||||
return (void *)&gpanel;
|
||||
|
||||
err_release_fb_mem:
|
||||
free(par->vram_virt);
|
||||
|
||||
err_release_fb:
|
||||
free(da8xx_fb_info);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void video_set_lut(unsigned int index, /* color number */
|
||||
unsigned char r, /* red */
|
||||
unsigned char g, /* green */
|
||||
unsigned char b /* blue */
|
||||
)
|
||||
{
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
void da8xx_video_init(const struct da8xx_panel *panel, int bits_pixel)
|
||||
{
|
||||
lcd_panel = panel;
|
||||
bits_x_pixel = bits_pixel;
|
||||
}
|
||||
144
common/package/boot/uboot-ipq40xx/src/drivers/video/exynos_fb.c
Normal file
144
common/package/boot/uboot-ipq40xx/src/drivers/video/exynos_fb.c
Normal file
|
|
@ -0,0 +1,144 @@
|
|||
/*
|
||||
* Copyright (C) 2012 Samsung Electronics
|
||||
*
|
||||
* Author: InKi Dae <inki.dae@samsung.com>
|
||||
* Author: Donghwa Lee <dh09.lee@samsung.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 <config.h>
|
||||
#include <common.h>
|
||||
#include <lcd.h>
|
||||
#include <asm/io.h>
|
||||
#include <asm/arch/cpu.h>
|
||||
#include <asm/arch/clock.h>
|
||||
#include <asm/arch/clk.h>
|
||||
#include <asm/arch/mipi_dsim.h>
|
||||
#include <asm/arch/system.h>
|
||||
|
||||
#include "exynos_fb.h"
|
||||
|
||||
int lcd_line_length;
|
||||
int lcd_color_fg;
|
||||
int lcd_color_bg;
|
||||
|
||||
void *lcd_base;
|
||||
void *lcd_console_address;
|
||||
|
||||
short console_col;
|
||||
short console_row;
|
||||
|
||||
static unsigned int panel_width, panel_height;
|
||||
|
||||
static void exynos_lcd_init_mem(void *lcdbase, vidinfo_t *vid)
|
||||
{
|
||||
unsigned long palette_size;
|
||||
unsigned int fb_size;
|
||||
|
||||
fb_size = vid->vl_row * vid->vl_col * (NBITS(vid->vl_bpix) >> 3);
|
||||
|
||||
lcd_base = lcdbase;
|
||||
|
||||
palette_size = NBITS(vid->vl_bpix) == 8 ? 256 : 16;
|
||||
|
||||
exynos_fimd_lcd_init_mem((unsigned long)lcd_base,
|
||||
(unsigned long)fb_size, palette_size);
|
||||
}
|
||||
|
||||
static void exynos_lcd_init(vidinfo_t *vid)
|
||||
{
|
||||
exynos_fimd_lcd_init(vid);
|
||||
}
|
||||
|
||||
static void draw_logo(void)
|
||||
{
|
||||
int x, y;
|
||||
ulong addr;
|
||||
|
||||
x = ((panel_width - panel_info.logo_width) >> 1);
|
||||
y = ((panel_height - panel_info.logo_height) >> 1) - 4;
|
||||
|
||||
addr = panel_info.logo_addr;
|
||||
bmp_display(addr, x, y);
|
||||
}
|
||||
|
||||
static void lcd_panel_on(vidinfo_t *vid)
|
||||
{
|
||||
udelay(vid->init_delay);
|
||||
|
||||
if (vid->backlight_reset)
|
||||
vid->backlight_reset();
|
||||
|
||||
if (vid->cfg_gpio)
|
||||
vid->cfg_gpio();
|
||||
|
||||
if (vid->lcd_power_on)
|
||||
vid->lcd_power_on();
|
||||
|
||||
udelay(vid->power_on_delay);
|
||||
|
||||
if (vid->reset_lcd) {
|
||||
vid->reset_lcd();
|
||||
udelay(vid->reset_delay);
|
||||
}
|
||||
|
||||
if (vid->backlight_on)
|
||||
vid->backlight_on(1);
|
||||
|
||||
if (vid->cfg_ldo)
|
||||
vid->cfg_ldo();
|
||||
|
||||
if (vid->enable_ldo)
|
||||
vid->enable_ldo(1);
|
||||
|
||||
if (vid->mipi_enabled)
|
||||
exynos_mipi_dsi_init();
|
||||
}
|
||||
|
||||
void lcd_ctrl_init(void *lcdbase)
|
||||
{
|
||||
set_system_display_ctrl();
|
||||
set_lcd_clk();
|
||||
|
||||
/* initialize parameters which is specific to panel. */
|
||||
init_panel_info(&panel_info);
|
||||
|
||||
panel_width = panel_info.vl_width;
|
||||
panel_height = panel_info.vl_height;
|
||||
|
||||
exynos_lcd_init_mem(lcdbase, &panel_info);
|
||||
|
||||
exynos_lcd_init(&panel_info);
|
||||
}
|
||||
|
||||
void lcd_enable(void)
|
||||
{
|
||||
if (panel_info.logo_on) {
|
||||
memset(lcd_base, 0, panel_width * panel_height *
|
||||
(NBITS(panel_info.vl_bpix) >> 3));
|
||||
|
||||
draw_logo();
|
||||
}
|
||||
|
||||
lcd_panel_on(&panel_info);
|
||||
}
|
||||
|
||||
/* dummy function */
|
||||
void lcd_setcolreg(ushort regno, ushort red, ushort green, ushort blue)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
|
@ -0,0 +1,54 @@
|
|||
/*
|
||||
* Copyright (C) 2012 Samsung Electronics
|
||||
*
|
||||
* Author: InKi Dae <inki.dae@samsung.com>
|
||||
* Author: Donghwa Lee <dh09.lee@samsung.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
|
||||
*/
|
||||
|
||||
#ifndef _EXYNOS_FB_H_
|
||||
#define _EXYNOS_FB_H_
|
||||
|
||||
#include <asm/arch/fb.h>
|
||||
|
||||
#define MAX_CLOCK (86 * 1000000)
|
||||
|
||||
enum exynos_cpu_auto_cmd_rate {
|
||||
DISABLE_AUTO_FRM,
|
||||
PER_TWO_FRM,
|
||||
PER_FOUR_FRM,
|
||||
PER_SIX_FRM,
|
||||
PER_EIGHT_FRM,
|
||||
PER_TEN_FRM,
|
||||
PER_TWELVE_FRM,
|
||||
PER_FOURTEEN_FRM,
|
||||
PER_SIXTEEN_FRM,
|
||||
PER_EIGHTEEN_FRM,
|
||||
PER_TWENTY_FRM,
|
||||
PER_TWENTY_TWO_FRM,
|
||||
PER_TWENTY_FOUR_FRM,
|
||||
PER_TWENTY_SIX_FRM,
|
||||
PER_TWENTY_EIGHT_FRM,
|
||||
PER_THIRTY_FRM,
|
||||
};
|
||||
|
||||
void exynos_fimd_lcd_init_mem(unsigned long screen_base, unsigned long fb_size,
|
||||
unsigned long palette_size);
|
||||
void exynos_fimd_lcd_init(vidinfo_t *vid);
|
||||
unsigned long exynos_fimd_calc_fbsize(void);
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,354 @@
|
|||
/*
|
||||
* Copyright (C) 2012 Samsung Electronics
|
||||
*
|
||||
* Author: InKi Dae <inki.dae@samsung.com>
|
||||
* Author: Donghwa Lee <dh09.lee@samsung.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 <config.h>
|
||||
#include <common.h>
|
||||
#include <asm/io.h>
|
||||
#include <lcd.h>
|
||||
#include <div64.h>
|
||||
#include <asm/arch/clk.h>
|
||||
#include <asm/arch/clock.h>
|
||||
#include <asm/arch/cpu.h>
|
||||
#include "exynos_fb.h"
|
||||
|
||||
static unsigned long *lcd_base_addr;
|
||||
static vidinfo_t *pvid;
|
||||
|
||||
void exynos_fimd_lcd_init_mem(u_long screen_base, u_long fb_size,
|
||||
u_long palette_size)
|
||||
{
|
||||
lcd_base_addr = (unsigned long *)screen_base;
|
||||
}
|
||||
|
||||
static void exynos_fimd_set_dualrgb(unsigned int enabled)
|
||||
{
|
||||
struct exynos4_fb *fimd_ctrl =
|
||||
(struct exynos4_fb *)samsung_get_base_fimd();
|
||||
unsigned int cfg = 0;
|
||||
|
||||
if (enabled) {
|
||||
cfg = EXYNOS_DUALRGB_BYPASS_DUAL | EXYNOS_DUALRGB_LINESPLIT |
|
||||
EXYNOS_DUALRGB_VDEN_EN_ENABLE;
|
||||
|
||||
/* in case of Line Split mode, MAIN_CNT doesn't neet to set. */
|
||||
cfg |= EXYNOS_DUALRGB_SUB_CNT(pvid->vl_col / 2) |
|
||||
EXYNOS_DUALRGB_MAIN_CNT(0);
|
||||
}
|
||||
|
||||
writel(cfg, &fimd_ctrl->dualrgb);
|
||||
}
|
||||
|
||||
static void exynos_fimd_set_par(unsigned int win_id)
|
||||
{
|
||||
unsigned int cfg = 0;
|
||||
struct exynos4_fb *fimd_ctrl =
|
||||
(struct exynos4_fb *)samsung_get_base_fimd();
|
||||
|
||||
/* set window control */
|
||||
cfg = readl((unsigned int)&fimd_ctrl->wincon0 +
|
||||
EXYNOS_WINCON(win_id));
|
||||
|
||||
cfg &= ~(EXYNOS_WINCON_BITSWP_ENABLE | EXYNOS_WINCON_BYTESWP_ENABLE |
|
||||
EXYNOS_WINCON_HAWSWP_ENABLE | EXYNOS_WINCON_WSWP_ENABLE |
|
||||
EXYNOS_WINCON_BURSTLEN_MASK | EXYNOS_WINCON_BPPMODE_MASK |
|
||||
EXYNOS_WINCON_INRGB_MASK | EXYNOS_WINCON_DATAPATH_MASK);
|
||||
|
||||
/* DATAPATH is DMA */
|
||||
cfg |= EXYNOS_WINCON_DATAPATH_DMA;
|
||||
|
||||
/* bpp is 32 */
|
||||
cfg |= EXYNOS_WINCON_WSWP_ENABLE;
|
||||
|
||||
/* dma burst is 16 */
|
||||
cfg |= EXYNOS_WINCON_BURSTLEN_16WORD;
|
||||
|
||||
/* pixel format is unpacked RGB888 */
|
||||
cfg |= EXYNOS_WINCON_BPPMODE_24BPP_888;
|
||||
|
||||
writel(cfg, (unsigned int)&fimd_ctrl->wincon0 +
|
||||
EXYNOS_WINCON(win_id));
|
||||
|
||||
/* set window position to x=0, y=0*/
|
||||
cfg = EXYNOS_VIDOSD_LEFT_X(0) | EXYNOS_VIDOSD_TOP_Y(0);
|
||||
writel(cfg, (unsigned int)&fimd_ctrl->vidosd0a +
|
||||
EXYNOS_VIDOSD(win_id));
|
||||
|
||||
cfg = EXYNOS_VIDOSD_RIGHT_X(pvid->vl_col - 1) |
|
||||
EXYNOS_VIDOSD_BOTTOM_Y(pvid->vl_row - 1);
|
||||
writel(cfg, (unsigned int)&fimd_ctrl->vidosd0b +
|
||||
EXYNOS_VIDOSD(win_id));
|
||||
|
||||
/* set window size for window0*/
|
||||
cfg = EXYNOS_VIDOSD_SIZE(pvid->vl_col * pvid->vl_row);
|
||||
writel(cfg, (unsigned int)&fimd_ctrl->vidosd0c +
|
||||
EXYNOS_VIDOSD(win_id));
|
||||
}
|
||||
|
||||
static void exynos_fimd_set_buffer_address(unsigned int win_id)
|
||||
{
|
||||
unsigned long start_addr, end_addr;
|
||||
struct exynos4_fb *fimd_ctrl =
|
||||
(struct exynos4_fb *)samsung_get_base_fimd();
|
||||
|
||||
start_addr = (unsigned long)lcd_base_addr;
|
||||
end_addr = start_addr + ((pvid->vl_col * (NBITS(pvid->vl_bpix) / 8)) *
|
||||
pvid->vl_row);
|
||||
|
||||
writel(start_addr, (unsigned int)&fimd_ctrl->vidw00add0b0 +
|
||||
EXYNOS_BUFFER_OFFSET(win_id));
|
||||
writel(end_addr, (unsigned int)&fimd_ctrl->vidw00add1b0 +
|
||||
EXYNOS_BUFFER_OFFSET(win_id));
|
||||
}
|
||||
|
||||
static void exynos_fimd_set_clock(vidinfo_t *pvid)
|
||||
{
|
||||
unsigned int cfg = 0, div = 0, remainder, remainder_div;
|
||||
unsigned long pixel_clock;
|
||||
unsigned long long src_clock;
|
||||
struct exynos4_fb *fimd_ctrl =
|
||||
(struct exynos4_fb *)samsung_get_base_fimd();
|
||||
|
||||
if (pvid->dual_lcd_enabled) {
|
||||
pixel_clock = pvid->vl_freq *
|
||||
(pvid->vl_hspw + pvid->vl_hfpd +
|
||||
pvid->vl_hbpd + pvid->vl_col / 2) *
|
||||
(pvid->vl_vspw + pvid->vl_vfpd +
|
||||
pvid->vl_vbpd + pvid->vl_row);
|
||||
} else if (pvid->interface_mode == FIMD_CPU_INTERFACE) {
|
||||
pixel_clock = pvid->vl_freq *
|
||||
pvid->vl_width * pvid->vl_height *
|
||||
(pvid->cs_setup + pvid->wr_setup +
|
||||
pvid->wr_act + pvid->wr_hold + 1);
|
||||
} else {
|
||||
pixel_clock = pvid->vl_freq *
|
||||
(pvid->vl_hspw + pvid->vl_hfpd +
|
||||
pvid->vl_hbpd + pvid->vl_col) *
|
||||
(pvid->vl_vspw + pvid->vl_vfpd +
|
||||
pvid->vl_vbpd + pvid->vl_row);
|
||||
}
|
||||
|
||||
cfg = readl(&fimd_ctrl->vidcon0);
|
||||
cfg &= ~(EXYNOS_VIDCON0_CLKSEL_MASK | EXYNOS_VIDCON0_CLKVALUP_MASK |
|
||||
EXYNOS_VIDCON0_CLKVAL_F(0xFF) | EXYNOS_VIDCON0_VCLKEN_MASK |
|
||||
EXYNOS_VIDCON0_CLKDIR_MASK);
|
||||
cfg |= (EXYNOS_VIDCON0_CLKSEL_SCLK | EXYNOS_VIDCON0_CLKVALUP_ALWAYS |
|
||||
EXYNOS_VIDCON0_VCLKEN_NORMAL | EXYNOS_VIDCON0_CLKDIR_DIVIDED);
|
||||
|
||||
if (pixel_clock > MAX_CLOCK)
|
||||
pixel_clock = MAX_CLOCK;
|
||||
|
||||
src_clock = (unsigned long long) get_lcd_clk();
|
||||
|
||||
/* get quotient and remainder. */
|
||||
remainder = do_div(src_clock, pixel_clock);
|
||||
div = src_clock;
|
||||
|
||||
remainder *= 10;
|
||||
remainder_div = remainder / pixel_clock;
|
||||
|
||||
/* round about one places of decimals. */
|
||||
if (remainder_div >= 5)
|
||||
div++;
|
||||
|
||||
/* in case of dual lcd mode. */
|
||||
if (pvid->dual_lcd_enabled)
|
||||
div--;
|
||||
|
||||
cfg |= EXYNOS_VIDCON0_CLKVAL_F(div - 1);
|
||||
writel(cfg, &fimd_ctrl->vidcon0);
|
||||
}
|
||||
|
||||
void exynos_set_trigger(void)
|
||||
{
|
||||
unsigned int cfg = 0;
|
||||
struct exynos4_fb *fimd_ctrl =
|
||||
(struct exynos4_fb *)samsung_get_base_fimd();
|
||||
|
||||
cfg = readl(&fimd_ctrl->trigcon);
|
||||
|
||||
cfg |= (EXYNOS_I80SOFT_TRIG_EN | EXYNOS_I80START_TRIG);
|
||||
|
||||
writel(cfg, &fimd_ctrl->trigcon);
|
||||
}
|
||||
|
||||
int exynos_is_i80_frame_done(void)
|
||||
{
|
||||
unsigned int cfg = 0;
|
||||
int status;
|
||||
struct exynos4_fb *fimd_ctrl =
|
||||
(struct exynos4_fb *)samsung_get_base_fimd();
|
||||
|
||||
cfg = readl(&fimd_ctrl->trigcon);
|
||||
|
||||
/* frame done func is valid only when TRIMODE[0] is set to 1. */
|
||||
status = (cfg & EXYNOS_I80STATUS_TRIG_DONE) ==
|
||||
EXYNOS_I80STATUS_TRIG_DONE;
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
static void exynos_fimd_lcd_on(void)
|
||||
{
|
||||
unsigned int cfg = 0;
|
||||
struct exynos4_fb *fimd_ctrl =
|
||||
(struct exynos4_fb *)samsung_get_base_fimd();
|
||||
|
||||
/* display on */
|
||||
cfg = readl(&fimd_ctrl->vidcon0);
|
||||
cfg |= (EXYNOS_VIDCON0_ENVID_ENABLE | EXYNOS_VIDCON0_ENVID_F_ENABLE);
|
||||
writel(cfg, &fimd_ctrl->vidcon0);
|
||||
}
|
||||
|
||||
static void exynos_fimd_window_on(unsigned int win_id)
|
||||
{
|
||||
unsigned int cfg = 0;
|
||||
struct exynos4_fb *fimd_ctrl =
|
||||
(struct exynos4_fb *)samsung_get_base_fimd();
|
||||
|
||||
/* enable window */
|
||||
cfg = readl((unsigned int)&fimd_ctrl->wincon0 +
|
||||
EXYNOS_WINCON(win_id));
|
||||
cfg |= EXYNOS_WINCON_ENWIN_ENABLE;
|
||||
writel(cfg, (unsigned int)&fimd_ctrl->wincon0 +
|
||||
EXYNOS_WINCON(win_id));
|
||||
|
||||
cfg = readl(&fimd_ctrl->winshmap);
|
||||
cfg |= EXYNOS_WINSHMAP_CH_ENABLE(win_id);
|
||||
writel(cfg, &fimd_ctrl->winshmap);
|
||||
}
|
||||
|
||||
void exynos_fimd_lcd_off(void)
|
||||
{
|
||||
unsigned int cfg = 0;
|
||||
struct exynos4_fb *fimd_ctrl =
|
||||
(struct exynos4_fb *)samsung_get_base_fimd();
|
||||
|
||||
cfg = readl(&fimd_ctrl->vidcon0);
|
||||
cfg &= (EXYNOS_VIDCON0_ENVID_DISABLE | EXYNOS_VIDCON0_ENVID_F_DISABLE);
|
||||
writel(cfg, &fimd_ctrl->vidcon0);
|
||||
}
|
||||
|
||||
void exynos_fimd_window_off(unsigned int win_id)
|
||||
{
|
||||
unsigned int cfg = 0;
|
||||
struct exynos4_fb *fimd_ctrl =
|
||||
(struct exynos4_fb *)samsung_get_base_fimd();
|
||||
|
||||
cfg = readl((unsigned int)&fimd_ctrl->wincon0 +
|
||||
EXYNOS_WINCON(win_id));
|
||||
cfg &= EXYNOS_WINCON_ENWIN_DISABLE;
|
||||
writel(cfg, (unsigned int)&fimd_ctrl->wincon0 +
|
||||
EXYNOS_WINCON(win_id));
|
||||
|
||||
cfg = readl(&fimd_ctrl->winshmap);
|
||||
cfg &= ~EXYNOS_WINSHMAP_CH_DISABLE(win_id);
|
||||
writel(cfg, &fimd_ctrl->winshmap);
|
||||
}
|
||||
|
||||
void exynos_fimd_lcd_init(vidinfo_t *vid)
|
||||
{
|
||||
unsigned int cfg = 0, rgb_mode;
|
||||
struct exynos4_fb *fimd_ctrl =
|
||||
(struct exynos4_fb *)samsung_get_base_fimd();
|
||||
|
||||
/* store panel info to global variable */
|
||||
pvid = vid;
|
||||
|
||||
rgb_mode = vid->rgb_mode;
|
||||
|
||||
if (vid->interface_mode == FIMD_RGB_INTERFACE) {
|
||||
cfg |= EXYNOS_VIDCON0_VIDOUT_RGB;
|
||||
writel(cfg, &fimd_ctrl->vidcon0);
|
||||
|
||||
cfg = readl(&fimd_ctrl->vidcon2);
|
||||
cfg &= ~(EXYNOS_VIDCON2_WB_MASK |
|
||||
EXYNOS_VIDCON2_TVFORMATSEL_MASK |
|
||||
EXYNOS_VIDCON2_TVFORMATSEL_YUV_MASK);
|
||||
cfg |= EXYNOS_VIDCON2_WB_DISABLE;
|
||||
writel(cfg, &fimd_ctrl->vidcon2);
|
||||
|
||||
/* set polarity */
|
||||
cfg = 0;
|
||||
if (!pvid->vl_clkp)
|
||||
cfg |= EXYNOS_VIDCON1_IVCLK_RISING_EDGE;
|
||||
if (!pvid->vl_hsp)
|
||||
cfg |= EXYNOS_VIDCON1_IHSYNC_INVERT;
|
||||
if (!pvid->vl_vsp)
|
||||
cfg |= EXYNOS_VIDCON1_IVSYNC_INVERT;
|
||||
if (!pvid->vl_dp)
|
||||
cfg |= EXYNOS_VIDCON1_IVDEN_INVERT;
|
||||
|
||||
writel(cfg, &fimd_ctrl->vidcon1);
|
||||
|
||||
/* set timing */
|
||||
cfg = EXYNOS_VIDTCON0_VFPD(pvid->vl_vfpd - 1);
|
||||
cfg |= EXYNOS_VIDTCON0_VBPD(pvid->vl_vbpd - 1);
|
||||
cfg |= EXYNOS_VIDTCON0_VSPW(pvid->vl_vspw - 1);
|
||||
writel(cfg, &fimd_ctrl->vidtcon0);
|
||||
|
||||
cfg = EXYNOS_VIDTCON1_HFPD(pvid->vl_hfpd - 1);
|
||||
cfg |= EXYNOS_VIDTCON1_HBPD(pvid->vl_hbpd - 1);
|
||||
cfg |= EXYNOS_VIDTCON1_HSPW(pvid->vl_hspw - 1);
|
||||
|
||||
writel(cfg, &fimd_ctrl->vidtcon1);
|
||||
|
||||
/* set lcd size */
|
||||
cfg = EXYNOS_VIDTCON2_HOZVAL(pvid->vl_col - 1);
|
||||
cfg |= EXYNOS_VIDTCON2_LINEVAL(pvid->vl_row - 1);
|
||||
|
||||
writel(cfg, &fimd_ctrl->vidtcon2);
|
||||
}
|
||||
|
||||
/* set display mode */
|
||||
cfg = readl(&fimd_ctrl->vidcon0);
|
||||
cfg &= ~EXYNOS_VIDCON0_PNRMODE_MASK;
|
||||
cfg |= (rgb_mode << EXYNOS_VIDCON0_PNRMODE_SHIFT);
|
||||
writel(cfg, &fimd_ctrl->vidcon0);
|
||||
|
||||
/* set par */
|
||||
exynos_fimd_set_par(pvid->win_id);
|
||||
|
||||
/* set memory address */
|
||||
exynos_fimd_set_buffer_address(pvid->win_id);
|
||||
|
||||
/* set buffer size */
|
||||
cfg = EXYNOS_VIDADDR_PAGEWIDTH(pvid->vl_col * NBITS(pvid->vl_bpix) / 8);
|
||||
writel(cfg, (unsigned int)&fimd_ctrl->vidw00add2 +
|
||||
EXYNOS_BUFFER_SIZE(pvid->win_id));
|
||||
|
||||
/* set clock */
|
||||
exynos_fimd_set_clock(pvid);
|
||||
|
||||
/* set rgb mode to dual lcd. */
|
||||
exynos_fimd_set_dualrgb(pvid->dual_lcd_enabled);
|
||||
|
||||
/* display on */
|
||||
exynos_fimd_lcd_on();
|
||||
|
||||
/* window on */
|
||||
exynos_fimd_window_on(pvid->win_id);
|
||||
}
|
||||
|
||||
unsigned long exynos_fimd_calc_fbsize(void)
|
||||
{
|
||||
return pvid->vl_col * pvid->vl_row * (NBITS(pvid->vl_bpix) / 8);
|
||||
}
|
||||
|
|
@ -0,0 +1,253 @@
|
|||
/*
|
||||
* Copyright (C) 2012 Samsung Electronics
|
||||
*
|
||||
* Author: InKi Dae <inki.dae@samsung.com>
|
||||
* Author: Donghwa Lee <dh09.lee@samsung.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 <common.h>
|
||||
#include <malloc.h>
|
||||
#include <linux/err.h>
|
||||
#include <asm/arch/dsim.h>
|
||||
#include <asm/arch/mipi_dsim.h>
|
||||
#include <asm/arch/power.h>
|
||||
#include <asm/arch/cpu.h>
|
||||
#include <asm/arch/clk.h>
|
||||
|
||||
#include "exynos_mipi_dsi_lowlevel.h"
|
||||
#include "exynos_mipi_dsi_common.h"
|
||||
|
||||
#define master_to_driver(a) (a->dsim_lcd_drv)
|
||||
#define master_to_device(a) (a->dsim_lcd_dev)
|
||||
|
||||
static struct exynos_platform_mipi_dsim *dsim_pd;
|
||||
|
||||
struct mipi_dsim_ddi {
|
||||
int bus_id;
|
||||
struct list_head list;
|
||||
struct mipi_dsim_lcd_device *dsim_lcd_dev;
|
||||
struct mipi_dsim_lcd_driver *dsim_lcd_drv;
|
||||
};
|
||||
|
||||
static LIST_HEAD(dsim_ddi_list);
|
||||
static LIST_HEAD(dsim_lcd_dev_list);
|
||||
|
||||
int exynos_mipi_dsi_register_lcd_device(struct mipi_dsim_lcd_device *lcd_dev)
|
||||
{
|
||||
struct mipi_dsim_ddi *dsim_ddi;
|
||||
|
||||
if (!lcd_dev) {
|
||||
debug("mipi_dsim_lcd_device is NULL.\n");
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
if (!lcd_dev->name) {
|
||||
debug("dsim_lcd_device name is NULL.\n");
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
dsim_ddi = kzalloc(sizeof(struct mipi_dsim_ddi), GFP_KERNEL);
|
||||
if (!dsim_ddi) {
|
||||
debug("failed to allocate dsim_ddi object.\n");
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
dsim_ddi->dsim_lcd_dev = lcd_dev;
|
||||
|
||||
list_add_tail(&dsim_ddi->list, &dsim_ddi_list);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct mipi_dsim_ddi
|
||||
*exynos_mipi_dsi_find_lcd_device(struct mipi_dsim_lcd_driver *lcd_drv)
|
||||
{
|
||||
struct mipi_dsim_ddi *dsim_ddi;
|
||||
struct mipi_dsim_lcd_device *lcd_dev;
|
||||
|
||||
list_for_each_entry(dsim_ddi, &dsim_ddi_list, list) {
|
||||
lcd_dev = dsim_ddi->dsim_lcd_dev;
|
||||
if (!lcd_dev)
|
||||
continue;
|
||||
|
||||
if (lcd_drv->id >= 0) {
|
||||
if ((strcmp(lcd_drv->name, lcd_dev->name)) == 0 &&
|
||||
lcd_drv->id == lcd_dev->id) {
|
||||
/**
|
||||
* bus_id would be used to identify
|
||||
* connected bus.
|
||||
*/
|
||||
dsim_ddi->bus_id = lcd_dev->bus_id;
|
||||
|
||||
return dsim_ddi;
|
||||
}
|
||||
} else {
|
||||
if ((strcmp(lcd_drv->name, lcd_dev->name)) == 0) {
|
||||
/**
|
||||
* bus_id would be used to identify
|
||||
* connected bus.
|
||||
*/
|
||||
dsim_ddi->bus_id = lcd_dev->bus_id;
|
||||
|
||||
return dsim_ddi;
|
||||
}
|
||||
}
|
||||
|
||||
kfree(dsim_ddi);
|
||||
list_del(&dsim_ddi_list);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int exynos_mipi_dsi_register_lcd_driver(struct mipi_dsim_lcd_driver *lcd_drv)
|
||||
{
|
||||
struct mipi_dsim_ddi *dsim_ddi;
|
||||
|
||||
if (!lcd_drv) {
|
||||
debug("mipi_dsim_lcd_driver is NULL.\n");
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
if (!lcd_drv->name) {
|
||||
debug("dsim_lcd_driver name is NULL.\n");
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
dsim_ddi = exynos_mipi_dsi_find_lcd_device(lcd_drv);
|
||||
if (!dsim_ddi) {
|
||||
debug("mipi_dsim_ddi object not found.\n");
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
dsim_ddi->dsim_lcd_drv = lcd_drv;
|
||||
|
||||
debug("registered panel driver(%s) to mipi-dsi driver.\n",
|
||||
lcd_drv->name);
|
||||
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
struct mipi_dsim_ddi
|
||||
*exynos_mipi_dsi_bind_lcd_ddi(struct mipi_dsim_device *dsim,
|
||||
const char *name)
|
||||
{
|
||||
struct mipi_dsim_ddi *dsim_ddi;
|
||||
struct mipi_dsim_lcd_driver *lcd_drv;
|
||||
struct mipi_dsim_lcd_device *lcd_dev;
|
||||
|
||||
list_for_each_entry(dsim_ddi, &dsim_ddi_list, list) {
|
||||
lcd_drv = dsim_ddi->dsim_lcd_drv;
|
||||
lcd_dev = dsim_ddi->dsim_lcd_dev;
|
||||
if (!lcd_drv || !lcd_dev)
|
||||
continue;
|
||||
|
||||
debug("lcd_drv->id = %d, lcd_dev->id = %d\n",
|
||||
lcd_drv->id, lcd_dev->id);
|
||||
|
||||
if ((strcmp(lcd_drv->name, name) == 0)) {
|
||||
lcd_dev->master = dsim;
|
||||
|
||||
dsim->dsim_lcd_dev = lcd_dev;
|
||||
dsim->dsim_lcd_drv = lcd_drv;
|
||||
|
||||
return dsim_ddi;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* define MIPI-DSI Master operations. */
|
||||
static struct mipi_dsim_master_ops master_ops = {
|
||||
.cmd_write = exynos_mipi_dsi_wr_data,
|
||||
.get_dsim_frame_done = exynos_mipi_dsi_get_frame_done_status,
|
||||
.clear_dsim_frame_done = exynos_mipi_dsi_clear_frame_done,
|
||||
};
|
||||
|
||||
int exynos_mipi_dsi_init(void)
|
||||
{
|
||||
struct mipi_dsim_device *dsim;
|
||||
struct mipi_dsim_config *dsim_config;
|
||||
struct mipi_dsim_ddi *dsim_ddi;
|
||||
|
||||
dsim = kzalloc(sizeof(struct mipi_dsim_device), GFP_KERNEL);
|
||||
if (!dsim) {
|
||||
debug("failed to allocate dsim object.\n");
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
/* get mipi_dsim_config. */
|
||||
dsim_config = dsim_pd->dsim_config;
|
||||
if (dsim_config == NULL) {
|
||||
debug("failed to get dsim config data.\n");
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
dsim->pd = dsim_pd;
|
||||
dsim->dsim_config = dsim_config;
|
||||
dsim->master_ops = &master_ops;
|
||||
|
||||
/* bind lcd ddi matched with panel name. */
|
||||
dsim_ddi = exynos_mipi_dsi_bind_lcd_ddi(dsim, dsim_pd->lcd_panel_name);
|
||||
if (!dsim_ddi) {
|
||||
debug("mipi_dsim_ddi object not found.\n");
|
||||
return -ENOSYS;
|
||||
}
|
||||
if (dsim_pd->lcd_power)
|
||||
dsim_pd->lcd_power();
|
||||
|
||||
if (dsim_pd->mipi_power)
|
||||
dsim_pd->mipi_power();
|
||||
|
||||
/* phy_enable(unsigned int dev_index, unsigned int enable) */
|
||||
if (dsim_pd->phy_enable)
|
||||
dsim_pd->phy_enable(0, 1);
|
||||
|
||||
set_mipi_clk();
|
||||
|
||||
exynos_mipi_dsi_init_dsim(dsim);
|
||||
exynos_mipi_dsi_init_link(dsim);
|
||||
exynos_mipi_dsi_set_hs_enable(dsim);
|
||||
|
||||
/* set display timing. */
|
||||
exynos_mipi_dsi_set_display_mode(dsim, dsim->dsim_config);
|
||||
|
||||
/* initialize mipi-dsi client(lcd panel). */
|
||||
if (dsim_ddi->dsim_lcd_drv && dsim_ddi->dsim_lcd_drv->mipi_panel_init) {
|
||||
dsim_ddi->dsim_lcd_drv->mipi_panel_init(dsim);
|
||||
dsim_ddi->dsim_lcd_drv->mipi_display_on(dsim);
|
||||
}
|
||||
|
||||
debug("mipi-dsi driver(%s mode) has been probed.\n",
|
||||
(dsim_config->e_interface == DSIM_COMMAND) ?
|
||||
"CPU" : "RGB");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void exynos_set_dsim_platform_data(struct exynos_platform_mipi_dsim *pd)
|
||||
{
|
||||
if (pd == NULL) {
|
||||
debug("pd is NULL\n");
|
||||
return;
|
||||
}
|
||||
|
||||
dsim_pd = pd;
|
||||
}
|
||||
|
|
@ -0,0 +1,637 @@
|
|||
/*
|
||||
* Copyright (C) 2012 Samsung Electronics
|
||||
*
|
||||
* Author: InKi Dae <inki.dae@samsung.com>
|
||||
* Author: Donghwa Lee <dh09.lee@samsung.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 <common.h>
|
||||
#include <lcd.h>
|
||||
#include <linux/err.h>
|
||||
#include <asm/arch/dsim.h>
|
||||
#include <asm/arch/mipi_dsim.h>
|
||||
|
||||
#include "exynos_mipi_dsi_lowlevel.h"
|
||||
|
||||
#define MHZ (1000 * 1000)
|
||||
#define FIN_HZ (24 * MHZ)
|
||||
|
||||
#define DFIN_PLL_MIN_HZ (6 * MHZ)
|
||||
#define DFIN_PLL_MAX_HZ (12 * MHZ)
|
||||
|
||||
#define DFVCO_MIN_HZ (500 * MHZ)
|
||||
#define DFVCO_MAX_HZ (1000 * MHZ)
|
||||
|
||||
#define TRY_GET_FIFO_TIMEOUT (5000 * 2)
|
||||
|
||||
/* MIPI-DSIM status types. */
|
||||
enum {
|
||||
DSIM_STATE_INIT, /* should be initialized. */
|
||||
DSIM_STATE_STOP, /* CPU and LCDC are LP mode. */
|
||||
DSIM_STATE_HSCLKEN, /* HS clock was enabled. */
|
||||
DSIM_STATE_ULPS
|
||||
};
|
||||
|
||||
/* define DSI lane types. */
|
||||
enum {
|
||||
DSIM_LANE_CLOCK = (1 << 0),
|
||||
DSIM_LANE_DATA0 = (1 << 1),
|
||||
DSIM_LANE_DATA1 = (1 << 2),
|
||||
DSIM_LANE_DATA2 = (1 << 3),
|
||||
DSIM_LANE_DATA3 = (1 << 4)
|
||||
};
|
||||
|
||||
static unsigned int dpll_table[15] = {
|
||||
100, 120, 170, 220, 270,
|
||||
320, 390, 450, 510, 560,
|
||||
640, 690, 770, 870, 950
|
||||
};
|
||||
|
||||
static void exynos_mipi_dsi_long_data_wr(struct mipi_dsim_device *dsim,
|
||||
unsigned int data0, unsigned int data1)
|
||||
{
|
||||
unsigned int data_cnt = 0, payload = 0;
|
||||
|
||||
/* in case that data count is more then 4 */
|
||||
for (data_cnt = 0; data_cnt < data1; data_cnt += 4) {
|
||||
/*
|
||||
* after sending 4bytes per one time,
|
||||
* send remainder data less then 4.
|
||||
*/
|
||||
if ((data1 - data_cnt) < 4) {
|
||||
if ((data1 - data_cnt) == 3) {
|
||||
payload = *(u8 *)(data0 + data_cnt) |
|
||||
(*(u8 *)(data0 + (data_cnt + 1))) << 8 |
|
||||
(*(u8 *)(data0 + (data_cnt + 2))) << 16;
|
||||
debug("count = 3 payload = %x, %x %x %x\n",
|
||||
payload, *(u8 *)(data0 + data_cnt),
|
||||
*(u8 *)(data0 + (data_cnt + 1)),
|
||||
*(u8 *)(data0 + (data_cnt + 2)));
|
||||
} else if ((data1 - data_cnt) == 2) {
|
||||
payload = *(u8 *)(data0 + data_cnt) |
|
||||
(*(u8 *)(data0 + (data_cnt + 1))) << 8;
|
||||
debug("count = 2 payload = %x, %x %x\n", payload,
|
||||
*(u8 *)(data0 + data_cnt),
|
||||
*(u8 *)(data0 + (data_cnt + 1)));
|
||||
} else if ((data1 - data_cnt) == 1) {
|
||||
payload = *(u8 *)(data0 + data_cnt);
|
||||
}
|
||||
} else {
|
||||
/* send 4bytes per one time. */
|
||||
payload = *(u8 *)(data0 + data_cnt) |
|
||||
(*(u8 *)(data0 + (data_cnt + 1))) << 8 |
|
||||
(*(u8 *)(data0 + (data_cnt + 2))) << 16 |
|
||||
(*(u8 *)(data0 + (data_cnt + 3))) << 24;
|
||||
|
||||
debug("count = 4 payload = %x, %x %x %x %x\n",
|
||||
payload, *(u8 *)(data0 + data_cnt),
|
||||
*(u8 *)(data0 + (data_cnt + 1)),
|
||||
*(u8 *)(data0 + (data_cnt + 2)),
|
||||
*(u8 *)(data0 + (data_cnt + 3)));
|
||||
|
||||
}
|
||||
exynos_mipi_dsi_wr_tx_data(dsim, payload);
|
||||
}
|
||||
}
|
||||
|
||||
int exynos_mipi_dsi_wr_data(struct mipi_dsim_device *dsim, unsigned int data_id,
|
||||
unsigned int data0, unsigned int data1)
|
||||
{
|
||||
unsigned int timeout = TRY_GET_FIFO_TIMEOUT;
|
||||
unsigned long delay_val, delay;
|
||||
unsigned int check_rx_ack = 0;
|
||||
|
||||
if (dsim->state == DSIM_STATE_ULPS) {
|
||||
debug("state is ULPS.\n");
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
delay_val = MHZ / dsim->dsim_config->esc_clk;
|
||||
delay = 10 * delay_val;
|
||||
|
||||
mdelay(delay);
|
||||
|
||||
/* only if transfer mode is LPDT, wait SFR becomes empty. */
|
||||
if (dsim->state == DSIM_STATE_STOP) {
|
||||
while (!(exynos_mipi_dsi_get_fifo_state(dsim) &
|
||||
SFR_HEADER_EMPTY)) {
|
||||
if ((timeout--) > 0)
|
||||
mdelay(1);
|
||||
else {
|
||||
debug("SRF header fifo is not empty.\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
switch (data_id) {
|
||||
/* short packet types of packet types for command. */
|
||||
case MIPI_DSI_GENERIC_SHORT_WRITE_0_PARAM:
|
||||
case MIPI_DSI_GENERIC_SHORT_WRITE_1_PARAM:
|
||||
case MIPI_DSI_GENERIC_SHORT_WRITE_2_PARAM:
|
||||
case MIPI_DSI_DCS_SHORT_WRITE:
|
||||
case MIPI_DSI_DCS_SHORT_WRITE_PARAM:
|
||||
case MIPI_DSI_SET_MAXIMUM_RETURN_PACKET_SIZE:
|
||||
debug("data0 = %x data1 = %x\n",
|
||||
data0, data1);
|
||||
exynos_mipi_dsi_wr_tx_header(dsim, data_id, data0, data1);
|
||||
if (check_rx_ack) {
|
||||
/* process response func should be implemented */
|
||||
return 0;
|
||||
} else {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* general command */
|
||||
case MIPI_DSI_COLOR_MODE_OFF:
|
||||
case MIPI_DSI_COLOR_MODE_ON:
|
||||
case MIPI_DSI_SHUTDOWN_PERIPHERAL:
|
||||
case MIPI_DSI_TURN_ON_PERIPHERAL:
|
||||
exynos_mipi_dsi_wr_tx_header(dsim, data_id, data0, data1);
|
||||
if (check_rx_ack) {
|
||||
/* process response func should be implemented. */
|
||||
return 0;
|
||||
} else {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* packet types for video data */
|
||||
case MIPI_DSI_V_SYNC_START:
|
||||
case MIPI_DSI_V_SYNC_END:
|
||||
case MIPI_DSI_H_SYNC_START:
|
||||
case MIPI_DSI_H_SYNC_END:
|
||||
case MIPI_DSI_END_OF_TRANSMISSION:
|
||||
return 0;
|
||||
|
||||
/* short and response packet types for command */
|
||||
case MIPI_DSI_GENERIC_READ_REQUEST_0_PARAM:
|
||||
case MIPI_DSI_GENERIC_READ_REQUEST_1_PARAM:
|
||||
case MIPI_DSI_GENERIC_READ_REQUEST_2_PARAM:
|
||||
case MIPI_DSI_DCS_READ:
|
||||
exynos_mipi_dsi_clear_all_interrupt(dsim);
|
||||
exynos_mipi_dsi_wr_tx_header(dsim, data_id, data0, data1);
|
||||
/* process response func should be implemented. */
|
||||
return 0;
|
||||
|
||||
/* long packet type and null packet */
|
||||
case MIPI_DSI_NULL_PACKET:
|
||||
case MIPI_DSI_BLANKING_PACKET:
|
||||
return 0;
|
||||
case MIPI_DSI_GENERIC_LONG_WRITE:
|
||||
case MIPI_DSI_DCS_LONG_WRITE:
|
||||
{
|
||||
unsigned int data_cnt = 0, payload = 0;
|
||||
|
||||
/* if data count is less then 4, then send 3bytes data. */
|
||||
if (data1 < 4) {
|
||||
payload = *(u8 *)(data0) |
|
||||
*(u8 *)(data0 + 1) << 8 |
|
||||
*(u8 *)(data0 + 2) << 16;
|
||||
|
||||
exynos_mipi_dsi_wr_tx_data(dsim, payload);
|
||||
|
||||
debug("count = %d payload = %x,%x %x %x\n",
|
||||
data1, payload,
|
||||
*(u8 *)(data0 + data_cnt),
|
||||
*(u8 *)(data0 + (data_cnt + 1)),
|
||||
*(u8 *)(data0 + (data_cnt + 2)));
|
||||
} else {
|
||||
/* in case that data count is more then 4 */
|
||||
exynos_mipi_dsi_long_data_wr(dsim, data0, data1);
|
||||
}
|
||||
|
||||
/* put data into header fifo */
|
||||
exynos_mipi_dsi_wr_tx_header(dsim, data_id, data1 & 0xff,
|
||||
(data1 & 0xff00) >> 8);
|
||||
|
||||
}
|
||||
if (check_rx_ack)
|
||||
/* process response func should be implemented. */
|
||||
return 0;
|
||||
else
|
||||
return -EINVAL;
|
||||
|
||||
/* packet typo for video data */
|
||||
case MIPI_DSI_PACKED_PIXEL_STREAM_16:
|
||||
case MIPI_DSI_PACKED_PIXEL_STREAM_18:
|
||||
case MIPI_DSI_PIXEL_STREAM_3BYTE_18:
|
||||
case MIPI_DSI_PACKED_PIXEL_STREAM_24:
|
||||
if (check_rx_ack) {
|
||||
/* process response func should be implemented. */
|
||||
return 0;
|
||||
} else {
|
||||
return -EINVAL;
|
||||
}
|
||||
default:
|
||||
debug("data id %x is not supported current DSI spec.\n",
|
||||
data_id);
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int exynos_mipi_dsi_pll_on(struct mipi_dsim_device *dsim, unsigned int enable)
|
||||
{
|
||||
int sw_timeout;
|
||||
|
||||
if (enable) {
|
||||
sw_timeout = 1000;
|
||||
|
||||
exynos_mipi_dsi_clear_interrupt(dsim);
|
||||
exynos_mipi_dsi_enable_pll(dsim, 1);
|
||||
while (1) {
|
||||
sw_timeout--;
|
||||
if (exynos_mipi_dsi_is_pll_stable(dsim))
|
||||
return 0;
|
||||
if (sw_timeout == 0)
|
||||
return -EINVAL;
|
||||
}
|
||||
} else
|
||||
exynos_mipi_dsi_enable_pll(dsim, 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
unsigned long exynos_mipi_dsi_change_pll(struct mipi_dsim_device *dsim,
|
||||
unsigned int pre_divider, unsigned int main_divider,
|
||||
unsigned int scaler)
|
||||
{
|
||||
unsigned long dfin_pll, dfvco, dpll_out;
|
||||
unsigned int i, freq_band = 0xf;
|
||||
|
||||
dfin_pll = (FIN_HZ / pre_divider);
|
||||
|
||||
/******************************************************
|
||||
* Serial Clock(=ByteClk X 8) FreqBand[3:0] *
|
||||
******************************************************
|
||||
* ~ 99.99 MHz 0000
|
||||
* 100 ~ 119.99 MHz 0001
|
||||
* 120 ~ 159.99 MHz 0010
|
||||
* 160 ~ 199.99 MHz 0011
|
||||
* 200 ~ 239.99 MHz 0100
|
||||
* 140 ~ 319.99 MHz 0101
|
||||
* 320 ~ 389.99 MHz 0110
|
||||
* 390 ~ 449.99 MHz 0111
|
||||
* 450 ~ 509.99 MHz 1000
|
||||
* 510 ~ 559.99 MHz 1001
|
||||
* 560 ~ 639.99 MHz 1010
|
||||
* 640 ~ 689.99 MHz 1011
|
||||
* 690 ~ 769.99 MHz 1100
|
||||
* 770 ~ 869.99 MHz 1101
|
||||
* 870 ~ 949.99 MHz 1110
|
||||
* 950 ~ 1000 MHz 1111
|
||||
******************************************************/
|
||||
if (dfin_pll < DFIN_PLL_MIN_HZ || dfin_pll > DFIN_PLL_MAX_HZ) {
|
||||
debug("fin_pll range should be 6MHz ~ 12MHz\n");
|
||||
exynos_mipi_dsi_enable_afc(dsim, 0, 0);
|
||||
} else {
|
||||
if (dfin_pll < 7 * MHZ)
|
||||
exynos_mipi_dsi_enable_afc(dsim, 1, 0x1);
|
||||
else if (dfin_pll < 8 * MHZ)
|
||||
exynos_mipi_dsi_enable_afc(dsim, 1, 0x0);
|
||||
else if (dfin_pll < 9 * MHZ)
|
||||
exynos_mipi_dsi_enable_afc(dsim, 1, 0x3);
|
||||
else if (dfin_pll < 10 * MHZ)
|
||||
exynos_mipi_dsi_enable_afc(dsim, 1, 0x2);
|
||||
else if (dfin_pll < 11 * MHZ)
|
||||
exynos_mipi_dsi_enable_afc(dsim, 1, 0x5);
|
||||
else
|
||||
exynos_mipi_dsi_enable_afc(dsim, 1, 0x4);
|
||||
}
|
||||
|
||||
dfvco = dfin_pll * main_divider;
|
||||
debug("dfvco = %lu, dfin_pll = %lu, main_divider = %d\n",
|
||||
dfvco, dfin_pll, main_divider);
|
||||
if (dfvco < DFVCO_MIN_HZ || dfvco > DFVCO_MAX_HZ)
|
||||
debug("fvco range should be 500MHz ~ 1000MHz\n");
|
||||
|
||||
dpll_out = dfvco / (1 << scaler);
|
||||
debug("dpll_out = %lu, dfvco = %lu, scaler = %d\n",
|
||||
dpll_out, dfvco, scaler);
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(dpll_table); i++) {
|
||||
if (dpll_out < dpll_table[i] * MHZ) {
|
||||
freq_band = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
debug("freq_band = %d\n", freq_band);
|
||||
|
||||
exynos_mipi_dsi_pll_freq(dsim, pre_divider, main_divider, scaler);
|
||||
|
||||
exynos_mipi_dsi_hs_zero_ctrl(dsim, 0);
|
||||
exynos_mipi_dsi_prep_ctrl(dsim, 0);
|
||||
|
||||
/* Freq Band */
|
||||
exynos_mipi_dsi_pll_freq_band(dsim, freq_band);
|
||||
|
||||
/* Stable time */
|
||||
exynos_mipi_dsi_pll_stable_time(dsim,
|
||||
dsim->dsim_config->pll_stable_time);
|
||||
|
||||
/* Enable PLL */
|
||||
debug("FOUT of mipi dphy pll is %luMHz\n",
|
||||
(dpll_out / MHZ));
|
||||
|
||||
return dpll_out;
|
||||
}
|
||||
|
||||
int exynos_mipi_dsi_set_clock(struct mipi_dsim_device *dsim,
|
||||
unsigned int byte_clk_sel, unsigned int enable)
|
||||
{
|
||||
unsigned int esc_div;
|
||||
unsigned long esc_clk_error_rate;
|
||||
unsigned long hs_clk = 0, byte_clk = 0, escape_clk = 0;
|
||||
|
||||
if (enable) {
|
||||
dsim->e_clk_src = byte_clk_sel;
|
||||
|
||||
/* Escape mode clock and byte clock source */
|
||||
exynos_mipi_dsi_set_byte_clock_src(dsim, byte_clk_sel);
|
||||
|
||||
/* DPHY, DSIM Link : D-PHY clock out */
|
||||
if (byte_clk_sel == DSIM_PLL_OUT_DIV8) {
|
||||
hs_clk = exynos_mipi_dsi_change_pll(dsim,
|
||||
dsim->dsim_config->p, dsim->dsim_config->m,
|
||||
dsim->dsim_config->s);
|
||||
if (hs_clk == 0) {
|
||||
debug("failed to get hs clock.\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
byte_clk = hs_clk / 8;
|
||||
exynos_mipi_dsi_enable_pll_bypass(dsim, 0);
|
||||
exynos_mipi_dsi_pll_on(dsim, 1);
|
||||
/* DPHY : D-PHY clock out, DSIM link : external clock out */
|
||||
} else if (byte_clk_sel == DSIM_EXT_CLK_DIV8)
|
||||
debug("not support EXT CLK source for MIPI DSIM\n");
|
||||
else if (byte_clk_sel == DSIM_EXT_CLK_BYPASS)
|
||||
debug("not support EXT CLK source for MIPI DSIM\n");
|
||||
|
||||
/* escape clock divider */
|
||||
esc_div = byte_clk / (dsim->dsim_config->esc_clk);
|
||||
debug("esc_div = %d, byte_clk = %lu, esc_clk = %lu\n",
|
||||
esc_div, byte_clk, dsim->dsim_config->esc_clk);
|
||||
if ((byte_clk / esc_div) >= (20 * MHZ) ||
|
||||
(byte_clk / esc_div) > dsim->dsim_config->esc_clk)
|
||||
esc_div += 1;
|
||||
|
||||
escape_clk = byte_clk / esc_div;
|
||||
debug("escape_clk = %lu, byte_clk = %lu, esc_div = %d\n",
|
||||
escape_clk, byte_clk, esc_div);
|
||||
|
||||
/* enable escape clock. */
|
||||
exynos_mipi_dsi_enable_byte_clock(dsim, 1);
|
||||
|
||||
/* enable byte clk and escape clock */
|
||||
exynos_mipi_dsi_set_esc_clk_prs(dsim, 1, esc_div);
|
||||
/* escape clock on lane */
|
||||
exynos_mipi_dsi_enable_esc_clk_on_lane(dsim,
|
||||
(DSIM_LANE_CLOCK | dsim->data_lane), 1);
|
||||
|
||||
debug("byte clock is %luMHz\n",
|
||||
(byte_clk / MHZ));
|
||||
debug("escape clock that user's need is %lu\n",
|
||||
(dsim->dsim_config->esc_clk / MHZ));
|
||||
debug("escape clock divider is %x\n", esc_div);
|
||||
debug("escape clock is %luMHz\n",
|
||||
((byte_clk / esc_div) / MHZ));
|
||||
|
||||
if ((byte_clk / esc_div) > escape_clk) {
|
||||
esc_clk_error_rate = escape_clk /
|
||||
(byte_clk / esc_div);
|
||||
debug("error rate is %lu over.\n",
|
||||
(esc_clk_error_rate / 100));
|
||||
} else if ((byte_clk / esc_div) < (escape_clk)) {
|
||||
esc_clk_error_rate = (byte_clk / esc_div) /
|
||||
escape_clk;
|
||||
debug("error rate is %lu under.\n",
|
||||
(esc_clk_error_rate / 100));
|
||||
}
|
||||
} else {
|
||||
exynos_mipi_dsi_enable_esc_clk_on_lane(dsim,
|
||||
(DSIM_LANE_CLOCK | dsim->data_lane), 0);
|
||||
exynos_mipi_dsi_set_esc_clk_prs(dsim, 0, 0);
|
||||
|
||||
/* disable escape clock. */
|
||||
exynos_mipi_dsi_enable_byte_clock(dsim, 0);
|
||||
|
||||
if (byte_clk_sel == DSIM_PLL_OUT_DIV8)
|
||||
exynos_mipi_dsi_pll_on(dsim, 0);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int exynos_mipi_dsi_init_dsim(struct mipi_dsim_device *dsim)
|
||||
{
|
||||
dsim->state = DSIM_STATE_INIT;
|
||||
|
||||
switch (dsim->dsim_config->e_no_data_lane) {
|
||||
case DSIM_DATA_LANE_1:
|
||||
dsim->data_lane = DSIM_LANE_DATA0;
|
||||
break;
|
||||
case DSIM_DATA_LANE_2:
|
||||
dsim->data_lane = DSIM_LANE_DATA0 | DSIM_LANE_DATA1;
|
||||
break;
|
||||
case DSIM_DATA_LANE_3:
|
||||
dsim->data_lane = DSIM_LANE_DATA0 | DSIM_LANE_DATA1 |
|
||||
DSIM_LANE_DATA2;
|
||||
break;
|
||||
case DSIM_DATA_LANE_4:
|
||||
dsim->data_lane = DSIM_LANE_DATA0 | DSIM_LANE_DATA1 |
|
||||
DSIM_LANE_DATA2 | DSIM_LANE_DATA3;
|
||||
break;
|
||||
default:
|
||||
debug("data lane is invalid.\n");
|
||||
return -EINVAL;
|
||||
};
|
||||
|
||||
exynos_mipi_dsi_sw_reset(dsim);
|
||||
exynos_mipi_dsi_dp_dn_swap(dsim, 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int exynos_mipi_dsi_enable_frame_done_int(struct mipi_dsim_device *dsim,
|
||||
unsigned int enable)
|
||||
{
|
||||
/* enable only frame done interrupt */
|
||||
exynos_mipi_dsi_set_interrupt_mask(dsim, INTMSK_FRAME_DONE, enable);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void convert_to_fb_videomode(struct fb_videomode *mode1,
|
||||
vidinfo_t *mode2)
|
||||
{
|
||||
mode1->xres = mode2->vl_width;
|
||||
mode1->yres = mode2->vl_height;
|
||||
mode1->upper_margin = mode2->vl_vfpd;
|
||||
mode1->lower_margin = mode2->vl_vbpd;
|
||||
mode1->left_margin = mode2->vl_hfpd;
|
||||
mode1->right_margin = mode2->vl_hbpd;
|
||||
mode1->vsync_len = mode2->vl_vspw;
|
||||
mode1->hsync_len = mode2->vl_hspw;
|
||||
}
|
||||
|
||||
int exynos_mipi_dsi_set_display_mode(struct mipi_dsim_device *dsim,
|
||||
struct mipi_dsim_config *dsim_config)
|
||||
{
|
||||
struct exynos_platform_mipi_dsim *dsim_pd;
|
||||
struct fb_videomode lcd_video;
|
||||
vidinfo_t *vid;
|
||||
|
||||
dsim_pd = (struct exynos_platform_mipi_dsim *)dsim->pd;
|
||||
vid = (vidinfo_t *)dsim_pd->lcd_panel_info;
|
||||
|
||||
convert_to_fb_videomode(&lcd_video, vid);
|
||||
|
||||
/* in case of VIDEO MODE (RGB INTERFACE), it sets polarities. */
|
||||
if (dsim->dsim_config->e_interface == (u32) DSIM_VIDEO) {
|
||||
if (dsim->dsim_config->auto_vertical_cnt == 0) {
|
||||
exynos_mipi_dsi_set_main_disp_vporch(dsim,
|
||||
vid->vl_cmd_allow_len,
|
||||
lcd_video.upper_margin,
|
||||
lcd_video.lower_margin);
|
||||
exynos_mipi_dsi_set_main_disp_hporch(dsim,
|
||||
lcd_video.left_margin,
|
||||
lcd_video.right_margin);
|
||||
exynos_mipi_dsi_set_main_disp_sync_area(dsim,
|
||||
lcd_video.vsync_len,
|
||||
lcd_video.hsync_len);
|
||||
}
|
||||
}
|
||||
|
||||
exynos_mipi_dsi_set_main_disp_resol(dsim, lcd_video.xres,
|
||||
lcd_video.yres);
|
||||
|
||||
exynos_mipi_dsi_display_config(dsim, dsim->dsim_config);
|
||||
|
||||
debug("lcd panel ==> width = %d, height = %d\n",
|
||||
lcd_video.xres, lcd_video.yres);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int exynos_mipi_dsi_init_link(struct mipi_dsim_device *dsim)
|
||||
{
|
||||
unsigned int time_out = 100;
|
||||
|
||||
switch (dsim->state) {
|
||||
case DSIM_STATE_INIT:
|
||||
exynos_mipi_dsi_init_fifo_pointer(dsim, 0x1f);
|
||||
|
||||
/* dsi configuration */
|
||||
exynos_mipi_dsi_init_config(dsim);
|
||||
exynos_mipi_dsi_enable_lane(dsim, DSIM_LANE_CLOCK, 1);
|
||||
exynos_mipi_dsi_enable_lane(dsim, dsim->data_lane, 1);
|
||||
|
||||
/* set clock configuration */
|
||||
exynos_mipi_dsi_set_clock(dsim,
|
||||
dsim->dsim_config->e_byte_clk, 1);
|
||||
|
||||
/* check clock and data lane state are stop state */
|
||||
while (!(exynos_mipi_dsi_is_lane_state(dsim))) {
|
||||
time_out--;
|
||||
if (time_out == 0) {
|
||||
debug("DSI Master is not stop state.\n");
|
||||
debug("Check initialization process\n");
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
dsim->state = DSIM_STATE_STOP;
|
||||
|
||||
/* BTA sequence counters */
|
||||
exynos_mipi_dsi_set_stop_state_counter(dsim,
|
||||
dsim->dsim_config->stop_holding_cnt);
|
||||
exynos_mipi_dsi_set_bta_timeout(dsim,
|
||||
dsim->dsim_config->bta_timeout);
|
||||
exynos_mipi_dsi_set_lpdr_timeout(dsim,
|
||||
dsim->dsim_config->rx_timeout);
|
||||
|
||||
return 0;
|
||||
default:
|
||||
debug("DSI Master is already init.\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int exynos_mipi_dsi_set_hs_enable(struct mipi_dsim_device *dsim)
|
||||
{
|
||||
if (dsim->state == DSIM_STATE_STOP) {
|
||||
if (dsim->e_clk_src != DSIM_EXT_CLK_BYPASS) {
|
||||
dsim->state = DSIM_STATE_HSCLKEN;
|
||||
|
||||
/* set LCDC and CPU transfer mode to HS. */
|
||||
exynos_mipi_dsi_set_lcdc_transfer_mode(dsim, 0);
|
||||
exynos_mipi_dsi_set_cpu_transfer_mode(dsim, 0);
|
||||
|
||||
exynos_mipi_dsi_enable_hs_clock(dsim, 1);
|
||||
|
||||
return 0;
|
||||
} else
|
||||
debug("clock source is external bypass.\n");
|
||||
} else
|
||||
debug("DSIM is not stop state.\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int exynos_mipi_dsi_set_data_transfer_mode(struct mipi_dsim_device *dsim,
|
||||
unsigned int mode)
|
||||
{
|
||||
if (mode) {
|
||||
if (dsim->state != DSIM_STATE_HSCLKEN) {
|
||||
debug("HS Clock lane is not enabled.\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
exynos_mipi_dsi_set_lcdc_transfer_mode(dsim, 0);
|
||||
} else {
|
||||
if (dsim->state == DSIM_STATE_INIT || dsim->state ==
|
||||
DSIM_STATE_ULPS) {
|
||||
debug("DSI Master is not STOP or HSDT state.\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
exynos_mipi_dsi_set_cpu_transfer_mode(dsim, 0);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int exynos_mipi_dsi_get_frame_done_status(struct mipi_dsim_device *dsim)
|
||||
{
|
||||
return _exynos_mipi_dsi_get_frame_done_status(dsim);
|
||||
}
|
||||
|
||||
int exynos_mipi_dsi_clear_frame_done(struct mipi_dsim_device *dsim)
|
||||
{
|
||||
_exynos_mipi_dsi_clear_frame_done(dsim);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -0,0 +1,48 @@
|
|||
/*
|
||||
* Copyright (C) 2012 Samsung Electronics
|
||||
*
|
||||
* Author: InKi Dae <inki.dae@samsung.com>
|
||||
* Author: Donghwa Lee <dh09.lee@samsung.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/fb.h>
|
||||
|
||||
#ifndef _EXYNOS_MIPI_DSI_COMMON_H
|
||||
#define _EXYNOS_MIPI_DSI_COMMON_H
|
||||
|
||||
int exynos_mipi_dsi_wr_data(struct mipi_dsim_device *dsim, unsigned int data_id,
|
||||
unsigned int data0, unsigned int data1);
|
||||
int exynos_mipi_dsi_pll_on(struct mipi_dsim_device *dsim, unsigned int enable);
|
||||
unsigned long exynos_mipi_dsi_change_pll(struct mipi_dsim_device *dsim,
|
||||
unsigned int pre_divider, unsigned int main_divider,
|
||||
unsigned int scaler);
|
||||
int exynos_mipi_dsi_set_clock(struct mipi_dsim_device *dsim,
|
||||
unsigned int byte_clk_sel, unsigned int enable);
|
||||
int exynos_mipi_dsi_init_dsim(struct mipi_dsim_device *dsim);
|
||||
int exynos_mipi_dsi_set_display_mode(struct mipi_dsim_device *dsim,
|
||||
struct mipi_dsim_config *dsim_info);
|
||||
int exynos_mipi_dsi_init_link(struct mipi_dsim_device *dsim);
|
||||
int exynos_mipi_dsi_set_hs_enable(struct mipi_dsim_device *dsim);
|
||||
int exynos_mipi_dsi_set_data_transfer_mode(struct mipi_dsim_device *dsim,
|
||||
unsigned int mode);
|
||||
int exynos_mipi_dsi_enable_frame_done_int(struct mipi_dsim_device *dsim,
|
||||
unsigned int enable);
|
||||
int exynos_mipi_dsi_get_frame_done_status(struct mipi_dsim_device *dsim);
|
||||
int exynos_mipi_dsi_clear_frame_done(struct mipi_dsim_device *dsim);
|
||||
|
||||
#endif /* _EXYNOS_MIPI_DSI_COMMON_H */
|
||||
|
|
@ -0,0 +1,652 @@
|
|||
/*
|
||||
* Copyright (C) 2012 Samsung Electronics
|
||||
*
|
||||
* Author: InKi Dae <inki.dae@samsung.com>
|
||||
* Author: Donghwa Lee <dh09.lee@samsung.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 <common.h>
|
||||
#include <asm/arch/dsim.h>
|
||||
#include <asm/arch/mipi_dsim.h>
|
||||
#include <asm/arch/power.h>
|
||||
#include <asm/arch/cpu.h>
|
||||
|
||||
#include "exynos_mipi_dsi_lowlevel.h"
|
||||
#include "exynos_mipi_dsi_common.h"
|
||||
|
||||
void exynos_mipi_dsi_func_reset(struct mipi_dsim_device *dsim)
|
||||
{
|
||||
unsigned int reg;
|
||||
|
||||
struct exynos_mipi_dsim *mipi_dsim =
|
||||
(struct exynos_mipi_dsim *)samsung_get_base_mipi_dsim();
|
||||
|
||||
reg = readl(&mipi_dsim->swrst);
|
||||
|
||||
reg |= DSIM_FUNCRST;
|
||||
|
||||
writel(reg, &mipi_dsim->swrst);
|
||||
}
|
||||
|
||||
void exynos_mipi_dsi_sw_reset(struct mipi_dsim_device *dsim)
|
||||
{
|
||||
unsigned int reg = 0;
|
||||
|
||||
struct exynos_mipi_dsim *mipi_dsim =
|
||||
(struct exynos_mipi_dsim *)samsung_get_base_mipi_dsim();
|
||||
|
||||
reg = readl(&mipi_dsim->swrst);
|
||||
|
||||
reg |= DSIM_SWRST;
|
||||
reg |= DSIM_FUNCRST;
|
||||
|
||||
writel(reg, &mipi_dsim->swrst);
|
||||
}
|
||||
|
||||
void exynos_mipi_dsi_sw_release(struct mipi_dsim_device *dsim)
|
||||
{
|
||||
struct exynos_mipi_dsim *mipi_dsim =
|
||||
(struct exynos_mipi_dsim *)samsung_get_base_mipi_dsim();
|
||||
unsigned int reg = readl(&mipi_dsim->intsrc);
|
||||
|
||||
reg |= INTSRC_SWRST_RELEASE;
|
||||
|
||||
writel(reg, &mipi_dsim->intsrc);
|
||||
}
|
||||
|
||||
void exynos_mipi_dsi_set_interrupt_mask(struct mipi_dsim_device *dsim,
|
||||
unsigned int mode, unsigned int mask)
|
||||
{
|
||||
struct exynos_mipi_dsim *mipi_dsim =
|
||||
(struct exynos_mipi_dsim *)samsung_get_base_mipi_dsim();
|
||||
unsigned int reg = readl(&mipi_dsim->intmsk);
|
||||
|
||||
if (mask)
|
||||
reg |= mode;
|
||||
else
|
||||
reg &= ~mode;
|
||||
|
||||
writel(reg, &mipi_dsim->intmsk);
|
||||
}
|
||||
|
||||
void exynos_mipi_dsi_init_fifo_pointer(struct mipi_dsim_device *dsim,
|
||||
unsigned int cfg)
|
||||
{
|
||||
unsigned int reg;
|
||||
struct exynos_mipi_dsim *mipi_dsim =
|
||||
(struct exynos_mipi_dsim *)samsung_get_base_mipi_dsim();
|
||||
|
||||
reg = readl(&mipi_dsim->fifoctrl);
|
||||
|
||||
writel(reg & ~(cfg), &mipi_dsim->fifoctrl);
|
||||
udelay(10 * 1000);
|
||||
reg |= cfg;
|
||||
|
||||
writel(reg, &mipi_dsim->fifoctrl);
|
||||
}
|
||||
|
||||
/*
|
||||
* this function set PLL P, M and S value in D-PHY
|
||||
*/
|
||||
void exynos_mipi_dsi_set_phy_tunning(struct mipi_dsim_device *dsim,
|
||||
unsigned int value)
|
||||
{
|
||||
struct exynos_mipi_dsim *mipi_dsim =
|
||||
(struct exynos_mipi_dsim *)samsung_get_base_mipi_dsim();
|
||||
|
||||
writel(DSIM_AFC_CTL(value), &mipi_dsim->phyacchr);
|
||||
}
|
||||
|
||||
void exynos_mipi_dsi_set_main_disp_resol(struct mipi_dsim_device *dsim,
|
||||
unsigned int width_resol, unsigned int height_resol)
|
||||
{
|
||||
unsigned int reg;
|
||||
struct exynos_mipi_dsim *mipi_dsim =
|
||||
(struct exynos_mipi_dsim *)samsung_get_base_mipi_dsim();
|
||||
|
||||
/* standby should be set after configuration so set to not ready*/
|
||||
reg = (readl(&mipi_dsim->mdresol)) & ~(DSIM_MAIN_STAND_BY);
|
||||
writel(reg, &mipi_dsim->mdresol);
|
||||
|
||||
/* reset resolution */
|
||||
reg &= ~(DSIM_MAIN_VRESOL(0x7ff) | DSIM_MAIN_HRESOL(0x7ff));
|
||||
reg |= DSIM_MAIN_VRESOL(height_resol) | DSIM_MAIN_HRESOL(width_resol);
|
||||
|
||||
reg |= DSIM_MAIN_STAND_BY;
|
||||
writel(reg, &mipi_dsim->mdresol);
|
||||
}
|
||||
|
||||
void exynos_mipi_dsi_set_main_disp_vporch(struct mipi_dsim_device *dsim,
|
||||
unsigned int cmd_allow, unsigned int vfront, unsigned int vback)
|
||||
{
|
||||
unsigned int reg;
|
||||
struct exynos_mipi_dsim *mipi_dsim =
|
||||
(struct exynos_mipi_dsim *)samsung_get_base_mipi_dsim();
|
||||
|
||||
reg = (readl(&mipi_dsim->mvporch)) &
|
||||
~((DSIM_CMD_ALLOW_MASK) | (DSIM_STABLE_VFP_MASK) |
|
||||
(DSIM_MAIN_VBP_MASK));
|
||||
|
||||
reg |= ((cmd_allow & 0xf) << DSIM_CMD_ALLOW_SHIFT) |
|
||||
((vfront & 0x7ff) << DSIM_STABLE_VFP_SHIFT) |
|
||||
((vback & 0x7ff) << DSIM_MAIN_VBP_SHIFT);
|
||||
|
||||
writel(reg, &mipi_dsim->mvporch);
|
||||
}
|
||||
|
||||
void exynos_mipi_dsi_set_main_disp_hporch(struct mipi_dsim_device *dsim,
|
||||
unsigned int front, unsigned int back)
|
||||
{
|
||||
unsigned int reg;
|
||||
struct exynos_mipi_dsim *mipi_dsim =
|
||||
(struct exynos_mipi_dsim *)samsung_get_base_mipi_dsim();
|
||||
|
||||
reg = (readl(&mipi_dsim->mhporch)) &
|
||||
~((DSIM_MAIN_HFP_MASK) | (DSIM_MAIN_HBP_MASK));
|
||||
|
||||
reg |= (front << DSIM_MAIN_HFP_SHIFT) | (back << DSIM_MAIN_HBP_SHIFT);
|
||||
|
||||
writel(reg, &mipi_dsim->mhporch);
|
||||
}
|
||||
|
||||
void exynos_mipi_dsi_set_main_disp_sync_area(struct mipi_dsim_device *dsim,
|
||||
unsigned int vert, unsigned int hori)
|
||||
{
|
||||
unsigned int reg;
|
||||
struct exynos_mipi_dsim *mipi_dsim =
|
||||
(struct exynos_mipi_dsim *)samsung_get_base_mipi_dsim();
|
||||
|
||||
reg = (readl(&mipi_dsim->msync)) &
|
||||
~((DSIM_MAIN_VSA_MASK) | (DSIM_MAIN_HSA_MASK));
|
||||
|
||||
reg |= ((vert & 0x3ff) << DSIM_MAIN_VSA_SHIFT) |
|
||||
(hori << DSIM_MAIN_HSA_SHIFT);
|
||||
|
||||
writel(reg, &mipi_dsim->msync);
|
||||
}
|
||||
|
||||
void exynos_mipi_dsi_set_sub_disp_resol(struct mipi_dsim_device *dsim,
|
||||
unsigned int vert, unsigned int hori)
|
||||
{
|
||||
unsigned int reg;
|
||||
struct exynos_mipi_dsim *mipi_dsim =
|
||||
(struct exynos_mipi_dsim *)samsung_get_base_mipi_dsim();
|
||||
|
||||
reg = (readl(&mipi_dsim->sdresol)) &
|
||||
~(DSIM_SUB_STANDY_MASK);
|
||||
|
||||
writel(reg, &mipi_dsim->sdresol);
|
||||
|
||||
reg &= ~(DSIM_SUB_VRESOL_MASK) | ~(DSIM_SUB_HRESOL_MASK);
|
||||
reg |= ((vert & 0x7ff) << DSIM_SUB_VRESOL_SHIFT) |
|
||||
((hori & 0x7ff) << DSIM_SUB_HRESOL_SHIFT);
|
||||
writel(reg, &mipi_dsim->sdresol);
|
||||
|
||||
/* DSIM STANDBY */
|
||||
reg |= (1 << DSIM_SUB_STANDY_SHIFT);
|
||||
writel(reg, &mipi_dsim->sdresol);
|
||||
}
|
||||
|
||||
void exynos_mipi_dsi_init_config(struct mipi_dsim_device *dsim)
|
||||
{
|
||||
struct mipi_dsim_config *dsim_config = dsim->dsim_config;
|
||||
struct exynos_mipi_dsim *mipi_dsim =
|
||||
(struct exynos_mipi_dsim *)samsung_get_base_mipi_dsim();
|
||||
unsigned int cfg = (readl(&mipi_dsim->config)) &
|
||||
~((1 << DSIM_EOT_PACKET_SHIFT) |
|
||||
(0x1f << DSIM_HSA_MODE_SHIFT) |
|
||||
(0x3 << DSIM_NUM_OF_DATALANE_SHIFT));
|
||||
|
||||
cfg |= (dsim_config->auto_flush << DSIM_AUTO_FLUSH_SHIFT) |
|
||||
(dsim_config->eot_disable << DSIM_EOT_PACKET_SHIFT) |
|
||||
(dsim_config->auto_vertical_cnt << DSIM_AUTO_MODE_SHIFT) |
|
||||
(dsim_config->hse << DSIM_HSE_MODE_SHIFT) |
|
||||
(dsim_config->hfp << DSIM_HFP_MODE_SHIFT) |
|
||||
(dsim_config->hbp << DSIM_HBP_MODE_SHIFT) |
|
||||
(dsim_config->hsa << DSIM_HSA_MODE_SHIFT) |
|
||||
(dsim_config->e_no_data_lane << DSIM_NUM_OF_DATALANE_SHIFT);
|
||||
|
||||
writel(cfg, &mipi_dsim->config);
|
||||
}
|
||||
|
||||
void exynos_mipi_dsi_display_config(struct mipi_dsim_device *dsim,
|
||||
struct mipi_dsim_config *dsim_config)
|
||||
{
|
||||
struct exynos_mipi_dsim *mipi_dsim =
|
||||
(struct exynos_mipi_dsim *)samsung_get_base_mipi_dsim();
|
||||
|
||||
u32 reg = (readl(&mipi_dsim->config)) &
|
||||
~((0x3 << DSIM_BURST_MODE_SHIFT) | (1 << DSIM_VIDEO_MODE_SHIFT)
|
||||
| (0x3 << DSIM_MAINVC_SHIFT) | (0x7 << DSIM_MAINPIX_SHIFT)
|
||||
| (0x3 << DSIM_SUBVC_SHIFT) | (0x7 << DSIM_SUBPIX_SHIFT));
|
||||
|
||||
if (dsim_config->e_interface == DSIM_VIDEO)
|
||||
reg |= (1 << DSIM_VIDEO_MODE_SHIFT);
|
||||
else if (dsim_config->e_interface == DSIM_COMMAND)
|
||||
reg &= ~(1 << DSIM_VIDEO_MODE_SHIFT);
|
||||
else {
|
||||
printf("unknown lcd type.\n");
|
||||
return;
|
||||
}
|
||||
|
||||
/* main lcd */
|
||||
reg |= ((u8) (dsim_config->e_burst_mode) & 0x3) << DSIM_BURST_MODE_SHIFT
|
||||
| ((u8) (dsim_config->e_virtual_ch) & 0x3) << DSIM_MAINVC_SHIFT
|
||||
| ((u8) (dsim_config->e_pixel_format) & 0x7) << DSIM_MAINPIX_SHIFT;
|
||||
|
||||
writel(reg, &mipi_dsim->config);
|
||||
}
|
||||
|
||||
void exynos_mipi_dsi_enable_lane(struct mipi_dsim_device *dsim,
|
||||
unsigned int lane, unsigned int enable)
|
||||
{
|
||||
unsigned int reg;
|
||||
struct exynos_mipi_dsim *mipi_dsim =
|
||||
(struct exynos_mipi_dsim *)samsung_get_base_mipi_dsim();
|
||||
|
||||
reg = readl(&mipi_dsim->config);
|
||||
|
||||
if (enable)
|
||||
reg |= DSIM_LANE_ENx(lane);
|
||||
else
|
||||
reg &= ~DSIM_LANE_ENx(lane);
|
||||
|
||||
writel(reg, &mipi_dsim->config);
|
||||
}
|
||||
|
||||
void exynos_mipi_dsi_set_data_lane_number(struct mipi_dsim_device *dsim,
|
||||
unsigned int count)
|
||||
{
|
||||
unsigned int cfg;
|
||||
struct exynos_mipi_dsim *mipi_dsim =
|
||||
(struct exynos_mipi_dsim *)samsung_get_base_mipi_dsim();
|
||||
|
||||
/* get the data lane number. */
|
||||
cfg = DSIM_NUM_OF_DATA_LANE(count);
|
||||
|
||||
writel(cfg, &mipi_dsim->config);
|
||||
}
|
||||
|
||||
void exynos_mipi_dsi_enable_afc(struct mipi_dsim_device *dsim,
|
||||
unsigned int enable, unsigned int afc_code)
|
||||
{
|
||||
struct exynos_mipi_dsim *mipi_dsim =
|
||||
(struct exynos_mipi_dsim *)samsung_get_base_mipi_dsim();
|
||||
unsigned int reg = readl(&mipi_dsim->phyacchr);
|
||||
|
||||
reg = 0;
|
||||
|
||||
if (enable) {
|
||||
reg |= DSIM_AFC_EN;
|
||||
reg &= ~(0x7 << DSIM_AFC_CTL_SHIFT);
|
||||
reg |= DSIM_AFC_CTL(afc_code);
|
||||
} else
|
||||
reg &= ~DSIM_AFC_EN;
|
||||
|
||||
writel(reg, &mipi_dsim->phyacchr);
|
||||
}
|
||||
|
||||
void exynos_mipi_dsi_enable_pll_bypass(struct mipi_dsim_device *dsim,
|
||||
unsigned int enable)
|
||||
{
|
||||
struct exynos_mipi_dsim *mipi_dsim =
|
||||
(struct exynos_mipi_dsim *)samsung_get_base_mipi_dsim();
|
||||
unsigned int reg = (readl(&mipi_dsim->clkctrl)) &
|
||||
~(DSIM_PLL_BYPASS_EXTERNAL);
|
||||
|
||||
reg |= enable << DSIM_PLL_BYPASS_SHIFT;
|
||||
|
||||
writel(reg, &mipi_dsim->clkctrl);
|
||||
}
|
||||
|
||||
void exynos_mipi_dsi_pll_freq_band(struct mipi_dsim_device *dsim,
|
||||
unsigned int freq_band)
|
||||
{
|
||||
struct exynos_mipi_dsim *mipi_dsim =
|
||||
(struct exynos_mipi_dsim *)samsung_get_base_mipi_dsim();
|
||||
unsigned int reg = (readl(&mipi_dsim->pllctrl)) &
|
||||
~(0x1f << DSIM_FREQ_BAND_SHIFT);
|
||||
|
||||
reg |= ((freq_band & 0x1f) << DSIM_FREQ_BAND_SHIFT);
|
||||
|
||||
writel(reg, &mipi_dsim->pllctrl);
|
||||
}
|
||||
|
||||
void exynos_mipi_dsi_pll_freq(struct mipi_dsim_device *dsim,
|
||||
unsigned int pre_divider, unsigned int main_divider,
|
||||
unsigned int scaler)
|
||||
{
|
||||
struct exynos_mipi_dsim *mipi_dsim =
|
||||
(struct exynos_mipi_dsim *)samsung_get_base_mipi_dsim();
|
||||
unsigned int reg = (readl(&mipi_dsim->pllctrl)) &
|
||||
~(0x7ffff << 1);
|
||||
|
||||
reg |= ((pre_divider & 0x3f) << DSIM_PREDIV_SHIFT) |
|
||||
((main_divider & 0x1ff) << DSIM_MAIN_SHIFT) |
|
||||
((scaler & 0x7) << DSIM_SCALER_SHIFT);
|
||||
|
||||
writel(reg, &mipi_dsim->pllctrl);
|
||||
}
|
||||
|
||||
void exynos_mipi_dsi_pll_stable_time(struct mipi_dsim_device *dsim,
|
||||
unsigned int lock_time)
|
||||
{
|
||||
struct exynos_mipi_dsim *mipi_dsim =
|
||||
(struct exynos_mipi_dsim *)samsung_get_base_mipi_dsim();
|
||||
|
||||
writel(lock_time, &mipi_dsim->plltmr);
|
||||
}
|
||||
|
||||
void exynos_mipi_dsi_enable_pll(struct mipi_dsim_device *dsim,
|
||||
unsigned int enable)
|
||||
{
|
||||
struct exynos_mipi_dsim *mipi_dsim =
|
||||
(struct exynos_mipi_dsim *)samsung_get_base_mipi_dsim();
|
||||
unsigned int reg = (readl(&mipi_dsim->pllctrl)) &
|
||||
~(0x1 << DSIM_PLL_EN_SHIFT);
|
||||
|
||||
reg |= ((enable & 0x1) << DSIM_PLL_EN_SHIFT);
|
||||
|
||||
writel(reg, &mipi_dsim->pllctrl);
|
||||
}
|
||||
|
||||
void exynos_mipi_dsi_set_byte_clock_src(struct mipi_dsim_device *dsim,
|
||||
unsigned int src)
|
||||
{
|
||||
struct exynos_mipi_dsim *mipi_dsim =
|
||||
(struct exynos_mipi_dsim *)samsung_get_base_mipi_dsim();
|
||||
unsigned int reg = (readl(&mipi_dsim->clkctrl)) &
|
||||
~(0x3 << DSIM_BYTE_CLK_SRC_SHIFT);
|
||||
|
||||
reg |= ((unsigned int) src) << DSIM_BYTE_CLK_SRC_SHIFT;
|
||||
|
||||
writel(reg, &mipi_dsim->clkctrl);
|
||||
}
|
||||
|
||||
void exynos_mipi_dsi_enable_byte_clock(struct mipi_dsim_device *dsim,
|
||||
unsigned int enable)
|
||||
{
|
||||
struct exynos_mipi_dsim *mipi_dsim =
|
||||
(struct exynos_mipi_dsim *)samsung_get_base_mipi_dsim();
|
||||
unsigned int reg = (readl(&mipi_dsim->clkctrl)) &
|
||||
~(1 << DSIM_BYTE_CLKEN_SHIFT);
|
||||
|
||||
reg |= enable << DSIM_BYTE_CLKEN_SHIFT;
|
||||
|
||||
writel(reg, &mipi_dsim->clkctrl);
|
||||
}
|
||||
|
||||
void exynos_mipi_dsi_set_esc_clk_prs(struct mipi_dsim_device *dsim,
|
||||
unsigned int enable, unsigned int prs_val)
|
||||
{
|
||||
struct exynos_mipi_dsim *mipi_dsim =
|
||||
(struct exynos_mipi_dsim *)samsung_get_base_mipi_dsim();
|
||||
unsigned int reg = (readl(&mipi_dsim->clkctrl)) &
|
||||
~((1 << DSIM_ESC_CLKEN_SHIFT) | (0xffff));
|
||||
|
||||
reg |= enable << DSIM_ESC_CLKEN_SHIFT;
|
||||
if (enable)
|
||||
reg |= prs_val;
|
||||
|
||||
writel(reg, &mipi_dsim->clkctrl);
|
||||
}
|
||||
|
||||
void exynos_mipi_dsi_enable_esc_clk_on_lane(struct mipi_dsim_device *dsim,
|
||||
unsigned int lane_sel, unsigned int enable)
|
||||
{
|
||||
struct exynos_mipi_dsim *mipi_dsim =
|
||||
(struct exynos_mipi_dsim *)samsung_get_base_mipi_dsim();
|
||||
unsigned int reg = readl(&mipi_dsim->clkctrl);
|
||||
|
||||
if (enable)
|
||||
reg |= DSIM_LANE_ESC_CLKEN(lane_sel);
|
||||
else
|
||||
reg &= ~DSIM_LANE_ESC_CLKEN(lane_sel);
|
||||
|
||||
writel(reg, &mipi_dsim->clkctrl);
|
||||
}
|
||||
|
||||
void exynos_mipi_dsi_force_dphy_stop_state(struct mipi_dsim_device *dsim,
|
||||
unsigned int enable)
|
||||
{
|
||||
struct exynos_mipi_dsim *mipi_dsim =
|
||||
(struct exynos_mipi_dsim *)samsung_get_base_mipi_dsim();
|
||||
unsigned int reg = (readl(&mipi_dsim->escmode)) &
|
||||
~(0x1 << DSIM_FORCE_STOP_STATE_SHIFT);
|
||||
|
||||
reg |= ((enable & 0x1) << DSIM_FORCE_STOP_STATE_SHIFT);
|
||||
|
||||
writel(reg, &mipi_dsim->escmode);
|
||||
}
|
||||
|
||||
unsigned int exynos_mipi_dsi_is_lane_state(struct mipi_dsim_device *dsim)
|
||||
{
|
||||
struct exynos_mipi_dsim *mipi_dsim =
|
||||
(struct exynos_mipi_dsim *)samsung_get_base_mipi_dsim();
|
||||
unsigned int reg = readl(&mipi_dsim->status);
|
||||
|
||||
/**
|
||||
* check clock and data lane states.
|
||||
* if MIPI-DSI controller was enabled at bootloader then
|
||||
* TX_READY_HS_CLK is enabled otherwise STOP_STATE_CLK.
|
||||
* so it should be checked for two case.
|
||||
*/
|
||||
if ((reg & DSIM_STOP_STATE_DAT(0xf)) &&
|
||||
((reg & DSIM_STOP_STATE_CLK) ||
|
||||
(reg & DSIM_TX_READY_HS_CLK)))
|
||||
return 1;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
void exynos_mipi_dsi_set_stop_state_counter(struct mipi_dsim_device *dsim,
|
||||
unsigned int cnt_val)
|
||||
{
|
||||
struct exynos_mipi_dsim *mipi_dsim =
|
||||
(struct exynos_mipi_dsim *)samsung_get_base_mipi_dsim();
|
||||
unsigned int reg = (readl(&mipi_dsim->escmode)) &
|
||||
~(0x7ff << DSIM_STOP_STATE_CNT_SHIFT);
|
||||
|
||||
reg |= ((cnt_val & 0x7ff) << DSIM_STOP_STATE_CNT_SHIFT);
|
||||
|
||||
writel(reg, &mipi_dsim->escmode);
|
||||
}
|
||||
|
||||
void exynos_mipi_dsi_set_bta_timeout(struct mipi_dsim_device *dsim,
|
||||
unsigned int timeout)
|
||||
{
|
||||
struct exynos_mipi_dsim *mipi_dsim =
|
||||
(struct exynos_mipi_dsim *)samsung_get_base_mipi_dsim();
|
||||
unsigned int reg = (readl(&mipi_dsim->timeout)) &
|
||||
~(0xff << DSIM_BTA_TOUT_SHIFT);
|
||||
|
||||
reg |= (timeout << DSIM_BTA_TOUT_SHIFT);
|
||||
|
||||
writel(reg, &mipi_dsim->timeout);
|
||||
}
|
||||
|
||||
void exynos_mipi_dsi_set_lpdr_timeout(struct mipi_dsim_device *dsim,
|
||||
unsigned int timeout)
|
||||
{
|
||||
struct exynos_mipi_dsim *mipi_dsim =
|
||||
(struct exynos_mipi_dsim *)samsung_get_base_mipi_dsim();
|
||||
unsigned int reg = (readl(&mipi_dsim->timeout)) &
|
||||
~(0xffff << DSIM_LPDR_TOUT_SHIFT);
|
||||
|
||||
reg |= (timeout << DSIM_LPDR_TOUT_SHIFT);
|
||||
|
||||
writel(reg, &mipi_dsim->timeout);
|
||||
}
|
||||
|
||||
void exynos_mipi_dsi_set_cpu_transfer_mode(struct mipi_dsim_device *dsim,
|
||||
unsigned int lp)
|
||||
{
|
||||
struct exynos_mipi_dsim *mipi_dsim =
|
||||
(struct exynos_mipi_dsim *)samsung_get_base_mipi_dsim();
|
||||
unsigned int reg = readl(&mipi_dsim->escmode);
|
||||
|
||||
reg &= ~DSIM_CMD_LPDT_LP;
|
||||
|
||||
if (lp)
|
||||
reg |= DSIM_CMD_LPDT_LP;
|
||||
|
||||
writel(reg, &mipi_dsim->escmode);
|
||||
}
|
||||
|
||||
void exynos_mipi_dsi_set_lcdc_transfer_mode(struct mipi_dsim_device *dsim,
|
||||
unsigned int lp)
|
||||
{
|
||||
struct exynos_mipi_dsim *mipi_dsim =
|
||||
(struct exynos_mipi_dsim *)samsung_get_base_mipi_dsim();
|
||||
unsigned int reg = readl(&mipi_dsim->escmode);
|
||||
|
||||
reg &= ~DSIM_TX_LPDT_LP;
|
||||
|
||||
if (lp)
|
||||
reg |= DSIM_TX_LPDT_LP;
|
||||
|
||||
writel(reg, &mipi_dsim->escmode);
|
||||
}
|
||||
|
||||
void exynos_mipi_dsi_enable_hs_clock(struct mipi_dsim_device *dsim,
|
||||
unsigned int enable)
|
||||
{
|
||||
struct exynos_mipi_dsim *mipi_dsim =
|
||||
(struct exynos_mipi_dsim *)samsung_get_base_mipi_dsim();
|
||||
unsigned int reg = (readl(&mipi_dsim->clkctrl)) &
|
||||
~(1 << DSIM_TX_REQUEST_HSCLK_SHIFT);
|
||||
|
||||
reg |= enable << DSIM_TX_REQUEST_HSCLK_SHIFT;
|
||||
|
||||
writel(reg, &mipi_dsim->clkctrl);
|
||||
}
|
||||
|
||||
void exynos_mipi_dsi_dp_dn_swap(struct mipi_dsim_device *dsim,
|
||||
unsigned int swap_en)
|
||||
{
|
||||
struct exynos_mipi_dsim *mipi_dsim =
|
||||
(struct exynos_mipi_dsim *)samsung_get_base_mipi_dsim();
|
||||
unsigned int reg = readl(&mipi_dsim->phyacchr1);
|
||||
|
||||
reg &= ~(0x3 << DSIM_DPDN_SWAP_DATA_SHIFT);
|
||||
reg |= (swap_en & 0x3) << DSIM_DPDN_SWAP_DATA_SHIFT;
|
||||
|
||||
writel(reg, &mipi_dsim->phyacchr1);
|
||||
}
|
||||
|
||||
void exynos_mipi_dsi_hs_zero_ctrl(struct mipi_dsim_device *dsim,
|
||||
unsigned int hs_zero)
|
||||
{
|
||||
struct exynos_mipi_dsim *mipi_dsim =
|
||||
(struct exynos_mipi_dsim *)samsung_get_base_mipi_dsim();
|
||||
unsigned int reg = (readl(&mipi_dsim->pllctrl)) &
|
||||
~(0xf << DSIM_ZEROCTRL_SHIFT);
|
||||
|
||||
reg |= ((hs_zero & 0xf) << DSIM_ZEROCTRL_SHIFT);
|
||||
|
||||
writel(reg, &mipi_dsim->pllctrl);
|
||||
}
|
||||
|
||||
void exynos_mipi_dsi_prep_ctrl(struct mipi_dsim_device *dsim, unsigned int prep)
|
||||
{
|
||||
struct exynos_mipi_dsim *mipi_dsim =
|
||||
(struct exynos_mipi_dsim *)samsung_get_base_mipi_dsim();
|
||||
unsigned int reg = (readl(&mipi_dsim->pllctrl)) &
|
||||
~(0x7 << DSIM_PRECTRL_SHIFT);
|
||||
|
||||
reg |= ((prep & 0x7) << DSIM_PRECTRL_SHIFT);
|
||||
|
||||
writel(reg, &mipi_dsim->pllctrl);
|
||||
}
|
||||
|
||||
void exynos_mipi_dsi_clear_interrupt(struct mipi_dsim_device *dsim)
|
||||
{
|
||||
struct exynos_mipi_dsim *mipi_dsim =
|
||||
(struct exynos_mipi_dsim *)samsung_get_base_mipi_dsim();
|
||||
unsigned int reg = readl(&mipi_dsim->intsrc);
|
||||
|
||||
reg |= INTSRC_PLL_STABLE;
|
||||
|
||||
writel(reg, &mipi_dsim->intsrc);
|
||||
}
|
||||
|
||||
void exynos_mipi_dsi_clear_all_interrupt(struct mipi_dsim_device *dsim)
|
||||
{
|
||||
struct exynos_mipi_dsim *mipi_dsim =
|
||||
(struct exynos_mipi_dsim *)samsung_get_base_mipi_dsim();
|
||||
|
||||
writel(0xffffffff, &mipi_dsim->intsrc);
|
||||
}
|
||||
|
||||
unsigned int exynos_mipi_dsi_is_pll_stable(struct mipi_dsim_device *dsim)
|
||||
{
|
||||
unsigned int reg;
|
||||
struct exynos_mipi_dsim *mipi_dsim =
|
||||
(struct exynos_mipi_dsim *)samsung_get_base_mipi_dsim();
|
||||
|
||||
reg = readl(&mipi_dsim->status);
|
||||
|
||||
return reg & DSIM_PLL_STABLE ? 1 : 0;
|
||||
}
|
||||
|
||||
unsigned int exynos_mipi_dsi_get_fifo_state(struct mipi_dsim_device *dsim)
|
||||
{
|
||||
struct exynos_mipi_dsim *mipi_dsim =
|
||||
(struct exynos_mipi_dsim *)samsung_get_base_mipi_dsim();
|
||||
|
||||
return readl(&mipi_dsim->fifoctrl) & ~(0x1f);
|
||||
}
|
||||
|
||||
void exynos_mipi_dsi_wr_tx_header(struct mipi_dsim_device *dsim,
|
||||
unsigned int di, unsigned int data0, unsigned int data1)
|
||||
{
|
||||
struct exynos_mipi_dsim *mipi_dsim =
|
||||
(struct exynos_mipi_dsim *)samsung_get_base_mipi_dsim();
|
||||
unsigned int reg = (DSIM_PKTHDR_DAT1(data1) | DSIM_PKTHDR_DAT0(data0) |
|
||||
DSIM_PKTHDR_DI(di));
|
||||
|
||||
writel(reg, &mipi_dsim->pkthdr);
|
||||
}
|
||||
|
||||
unsigned int _exynos_mipi_dsi_get_frame_done_status(struct mipi_dsim_device
|
||||
*dsim)
|
||||
{
|
||||
struct exynos_mipi_dsim *mipi_dsim =
|
||||
(struct exynos_mipi_dsim *)samsung_get_base_mipi_dsim();
|
||||
unsigned int reg = readl(&mipi_dsim->intsrc);
|
||||
|
||||
return (reg & INTSRC_FRAME_DONE) ? 1 : 0;
|
||||
}
|
||||
|
||||
void _exynos_mipi_dsi_clear_frame_done(struct mipi_dsim_device *dsim)
|
||||
{
|
||||
struct exynos_mipi_dsim *mipi_dsim =
|
||||
(struct exynos_mipi_dsim *)samsung_get_base_mipi_dsim();
|
||||
unsigned int reg = readl(&mipi_dsim->intsrc);
|
||||
|
||||
writel(reg | INTSRC_FRAME_DONE, &mipi_dsim->intsrc);
|
||||
}
|
||||
|
||||
void exynos_mipi_dsi_wr_tx_data(struct mipi_dsim_device *dsim,
|
||||
unsigned int tx_data)
|
||||
{
|
||||
struct exynos_mipi_dsim *mipi_dsim =
|
||||
(struct exynos_mipi_dsim *)samsung_get_base_mipi_dsim();
|
||||
|
||||
writel(tx_data, &mipi_dsim->payload);
|
||||
}
|
||||
|
|
@ -0,0 +1,111 @@
|
|||
/*
|
||||
* Copyright (C) 2012 Samsung Electronics
|
||||
*
|
||||
* Author: InKi Dae <inki.dae@samsung.com>
|
||||
* Author: Donghwa Lee <dh09.lee@samsung.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
|
||||
*/
|
||||
|
||||
#ifndef _EXYNOS_MIPI_DSI_LOWLEVEL_H
|
||||
#define _EXYNOS_MIPI_DSI_LOWLEVEL_H
|
||||
|
||||
void exynos_mipi_dsi_register(struct mipi_dsim_device *dsim);
|
||||
void exynos_mipi_dsi_func_reset(struct mipi_dsim_device *dsim);
|
||||
void exynos_mipi_dsi_sw_reset(struct mipi_dsim_device *dsim);
|
||||
void exynos_mipi_dsi_sw_release(struct mipi_dsim_device *dsim);
|
||||
void exynos_mipi_dsi_set_interrupt_mask(struct mipi_dsim_device *dsim,
|
||||
unsigned int mode, unsigned int mask);
|
||||
void exynos_mipi_dsi_set_data_lane_number(struct mipi_dsim_device *dsim,
|
||||
unsigned int count);
|
||||
void exynos_mipi_dsi_init_fifo_pointer(struct mipi_dsim_device *dsim,
|
||||
unsigned int cfg);
|
||||
void exynos_mipi_dsi_set_phy_tunning(struct mipi_dsim_device *dsim,
|
||||
unsigned int value);
|
||||
void exynos_mipi_dsi_set_phy_tunning(struct mipi_dsim_device *dsim,
|
||||
unsigned int value);
|
||||
void exynos_mipi_dsi_set_main_disp_resol(struct mipi_dsim_device *dsim,
|
||||
unsigned int width_resol, unsigned int height_resol);
|
||||
void exynos_mipi_dsi_set_main_disp_vporch(struct mipi_dsim_device *dsim,
|
||||
unsigned int cmd_allow, unsigned int vfront, unsigned int vback);
|
||||
void exynos_mipi_dsi_set_main_disp_hporch(struct mipi_dsim_device *dsim,
|
||||
unsigned int front, unsigned int back);
|
||||
void exynos_mipi_dsi_set_main_disp_sync_area(struct mipi_dsim_device *dsim,
|
||||
unsigned int vert, unsigned int hori);
|
||||
void exynos_mipi_dsi_set_sub_disp_resol(struct mipi_dsim_device *dsim,
|
||||
unsigned int vert, unsigned int hori);
|
||||
void exynos_mipi_dsi_init_config(struct mipi_dsim_device *dsim);
|
||||
void exynos_mipi_dsi_display_config(struct mipi_dsim_device *dsim,
|
||||
struct mipi_dsim_config *dsim_config);
|
||||
void exynos_mipi_dsi_set_data_lane_number(struct mipi_dsim_device *dsim,
|
||||
unsigned int count);
|
||||
void exynos_mipi_dsi_enable_lane(struct mipi_dsim_device *dsim,
|
||||
unsigned int lane, unsigned int enable);
|
||||
void exynos_mipi_dsi_enable_afc(struct mipi_dsim_device *dsim,
|
||||
unsigned int enable, unsigned int afc_code);
|
||||
void exynos_mipi_dsi_enable_pll_bypass(struct mipi_dsim_device *dsim,
|
||||
unsigned int enable);
|
||||
void exynos_mipi_dsi_pll_freq_band(struct mipi_dsim_device *dsim,
|
||||
unsigned int freq_band);
|
||||
void exynos_mipi_dsi_pll_freq(struct mipi_dsim_device *dsim,
|
||||
unsigned int pre_divider, unsigned int main_divider,
|
||||
unsigned int scaler);
|
||||
void exynos_mipi_dsi_pll_stable_time(struct mipi_dsim_device *dsim,
|
||||
unsigned int lock_time);
|
||||
void exynos_mipi_dsi_enable_pll(struct mipi_dsim_device *dsim,
|
||||
unsigned int enable);
|
||||
void exynos_mipi_dsi_set_byte_clock_src(struct mipi_dsim_device *dsim,
|
||||
unsigned int src);
|
||||
void exynos_mipi_dsi_enable_byte_clock(struct mipi_dsim_device *dsim,
|
||||
unsigned int enable);
|
||||
void exynos_mipi_dsi_set_esc_clk_prs(struct mipi_dsim_device *dsim,
|
||||
unsigned int enable, unsigned int prs_val);
|
||||
void exynos_mipi_dsi_enable_esc_clk_on_lane(struct mipi_dsim_device *dsim,
|
||||
unsigned int lane_sel, unsigned int enable);
|
||||
void exynos_mipi_dsi_force_dphy_stop_state(struct mipi_dsim_device *dsim,
|
||||
unsigned int enable);
|
||||
unsigned int exynos_mipi_dsi_is_lane_state(struct mipi_dsim_device *dsim);
|
||||
void exynos_mipi_dsi_set_stop_state_counter(struct mipi_dsim_device *dsim,
|
||||
unsigned int cnt_val);
|
||||
void exynos_mipi_dsi_set_bta_timeout(struct mipi_dsim_device *dsim,
|
||||
unsigned int timeout);
|
||||
void exynos_mipi_dsi_set_lpdr_timeout(struct mipi_dsim_device *dsim,
|
||||
unsigned int timeout);
|
||||
void exynos_mipi_dsi_set_lcdc_transfer_mode(struct mipi_dsim_device *dsim,
|
||||
unsigned int lp);
|
||||
void exynos_mipi_dsi_set_cpu_transfer_mode(struct mipi_dsim_device *dsim,
|
||||
unsigned int lp);
|
||||
void exynos_mipi_dsi_enable_hs_clock(struct mipi_dsim_device *dsim,
|
||||
unsigned int enable);
|
||||
void exynos_mipi_dsi_dp_dn_swap(struct mipi_dsim_device *dsim,
|
||||
unsigned int swap_en);
|
||||
void exynos_mipi_dsi_hs_zero_ctrl(struct mipi_dsim_device *dsim,
|
||||
unsigned int hs_zero);
|
||||
void exynos_mipi_dsi_prep_ctrl(struct mipi_dsim_device *dsim,
|
||||
unsigned int prep);
|
||||
void exynos_mipi_dsi_clear_interrupt(struct mipi_dsim_device *dsim);
|
||||
void exynos_mipi_dsi_clear_all_interrupt(struct mipi_dsim_device *dsim);
|
||||
unsigned int exynos_mipi_dsi_is_pll_stable(struct mipi_dsim_device *dsim);
|
||||
unsigned int exynos_mipi_dsi_get_fifo_state(struct mipi_dsim_device *dsim);
|
||||
unsigned int _exynos_mipi_dsi_get_frame_done_status(struct mipi_dsim_device
|
||||
*dsim);
|
||||
void _exynos_mipi_dsi_clear_frame_done(struct mipi_dsim_device *dsim);
|
||||
void exynos_mipi_dsi_wr_tx_header(struct mipi_dsim_device *dsim,
|
||||
unsigned int di, unsigned int data0, unsigned int data1);
|
||||
void exynos_mipi_dsi_wr_tx_data(struct mipi_dsim_device *dsim,
|
||||
unsigned int tx_data);
|
||||
|
||||
#endif /* _EXYNOS_MIPI_DSI_LOWLEVEL_H */
|
||||
450
common/package/boot/uboot-ipq40xx/src/drivers/video/fsl_diu_fb.c
Normal file
450
common/package/boot/uboot-ipq40xx/src/drivers/video/fsl_diu_fb.c
Normal file
|
|
@ -0,0 +1,450 @@
|
|||
/*
|
||||
* Copyright 2007, 2010-2011 Freescale Semiconductor, Inc.
|
||||
* Authors: York Sun <yorksun@freescale.com>
|
||||
* Timur Tabi <timur@freescale.com>
|
||||
*
|
||||
* FSL DIU Framebuffer driver
|
||||
*
|
||||
* See file CREDITS for list of people who contributed to this
|
||||
* project.
|
||||
*
|
||||
* 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 <common.h>
|
||||
#include <malloc.h>
|
||||
#include <asm/io.h>
|
||||
|
||||
#include "videomodes.h"
|
||||
#include <video_fb.h>
|
||||
#include <fsl_diu_fb.h>
|
||||
#include <linux/list.h>
|
||||
#include <linux/fb.h>
|
||||
|
||||
/* This setting is used for the ifm pdm360ng with PRIMEVIEW PM070WL3 */
|
||||
static struct fb_videomode fsl_diu_mode_800_480 = {
|
||||
.name = "800x480-60",
|
||||
.refresh = 60,
|
||||
.xres = 800,
|
||||
.yres = 480,
|
||||
.pixclock = 31250,
|
||||
.left_margin = 86,
|
||||
.right_margin = 42,
|
||||
.upper_margin = 33,
|
||||
.lower_margin = 10,
|
||||
.hsync_len = 128,
|
||||
.vsync_len = 2,
|
||||
.sync = 0,
|
||||
.vmode = FB_VMODE_NONINTERLACED
|
||||
};
|
||||
|
||||
/* For the SHARP LQ084S3LG01, used on the P1022DS board */
|
||||
static struct fb_videomode fsl_diu_mode_800_600 = {
|
||||
.name = "800x600-60",
|
||||
.refresh = 60,
|
||||
.xres = 800,
|
||||
.yres = 600,
|
||||
.pixclock = 25000,
|
||||
.left_margin = 88,
|
||||
.right_margin = 40,
|
||||
.upper_margin = 23,
|
||||
.lower_margin = 1,
|
||||
.hsync_len = 128,
|
||||
.vsync_len = 4,
|
||||
.sync = FB_SYNC_COMP_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
|
||||
.vmode = FB_VMODE_NONINTERLACED
|
||||
};
|
||||
|
||||
/*
|
||||
* These parameters give default parameters
|
||||
* for video output 1024x768,
|
||||
* FIXME - change timing to proper amounts
|
||||
* hsync 31.5kHz, vsync 60Hz
|
||||
*/
|
||||
static struct fb_videomode fsl_diu_mode_1024_768 = {
|
||||
.name = "1024x768-60",
|
||||
.refresh = 60,
|
||||
.xres = 1024,
|
||||
.yres = 768,
|
||||
.pixclock = 15385,
|
||||
.left_margin = 160,
|
||||
.right_margin = 24,
|
||||
.upper_margin = 29,
|
||||
.lower_margin = 3,
|
||||
.hsync_len = 136,
|
||||
.vsync_len = 6,
|
||||
.sync = FB_SYNC_COMP_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
|
||||
.vmode = FB_VMODE_NONINTERLACED
|
||||
};
|
||||
|
||||
static struct fb_videomode fsl_diu_mode_1280_1024 = {
|
||||
.name = "1280x1024-60",
|
||||
.refresh = 60,
|
||||
.xres = 1280,
|
||||
.yres = 1024,
|
||||
.pixclock = 9375,
|
||||
.left_margin = 38,
|
||||
.right_margin = 128,
|
||||
.upper_margin = 2,
|
||||
.lower_margin = 7,
|
||||
.hsync_len = 216,
|
||||
.vsync_len = 37,
|
||||
.sync = FB_SYNC_COMP_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
|
||||
.vmode = FB_VMODE_NONINTERLACED
|
||||
};
|
||||
|
||||
static struct fb_videomode fsl_diu_mode_1280_720 = {
|
||||
.name = "1280x720-60",
|
||||
.refresh = 60,
|
||||
.xres = 1280,
|
||||
.yres = 720,
|
||||
.pixclock = 13426,
|
||||
.left_margin = 192,
|
||||
.right_margin = 64,
|
||||
.upper_margin = 22,
|
||||
.lower_margin = 1,
|
||||
.hsync_len = 136,
|
||||
.vsync_len = 3,
|
||||
.sync = FB_SYNC_COMP_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
|
||||
.vmode = FB_VMODE_NONINTERLACED
|
||||
};
|
||||
|
||||
static struct fb_videomode fsl_diu_mode_1920_1080 = {
|
||||
.name = "1920x1080-60",
|
||||
.refresh = 60,
|
||||
.xres = 1920,
|
||||
.yres = 1080,
|
||||
.pixclock = 5787,
|
||||
.left_margin = 328,
|
||||
.right_margin = 120,
|
||||
.upper_margin = 34,
|
||||
.lower_margin = 1,
|
||||
.hsync_len = 208,
|
||||
.vsync_len = 3,
|
||||
.sync = FB_SYNC_COMP_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
|
||||
.vmode = FB_VMODE_NONINTERLACED
|
||||
};
|
||||
|
||||
/*
|
||||
* These are the fields of area descriptor(in DDR memory) for every plane
|
||||
*/
|
||||
struct diu_ad {
|
||||
/* Word 0(32-bit) in DDR memory */
|
||||
__le32 pix_fmt; /* hard coding pixel format */
|
||||
/* Word 1(32-bit) in DDR memory */
|
||||
__le32 addr;
|
||||
/* Word 2(32-bit) in DDR memory */
|
||||
__le32 src_size_g_alpha;
|
||||
/* Word 3(32-bit) in DDR memory */
|
||||
__le32 aoi_size;
|
||||
/* Word 4(32-bit) in DDR memory */
|
||||
__le32 offset_xyi;
|
||||
/* Word 5(32-bit) in DDR memory */
|
||||
__le32 offset_xyd;
|
||||
/* Word 6(32-bit) in DDR memory */
|
||||
__le32 ckmax_r:8;
|
||||
__le32 ckmax_g:8;
|
||||
__le32 ckmax_b:8;
|
||||
__le32 res9:8;
|
||||
/* Word 7(32-bit) in DDR memory */
|
||||
__le32 ckmin_r:8;
|
||||
__le32 ckmin_g:8;
|
||||
__le32 ckmin_b:8;
|
||||
__le32 res10:8;
|
||||
/* Word 8(32-bit) in DDR memory */
|
||||
__le32 next_ad;
|
||||
/* Word 9(32-bit) in DDR memory, just for 64-bit aligned */
|
||||
__le32 res[3];
|
||||
} __attribute__ ((packed));
|
||||
|
||||
/*
|
||||
* DIU register map
|
||||
*/
|
||||
struct diu {
|
||||
__be32 desc[3];
|
||||
__be32 gamma;
|
||||
__be32 pallete;
|
||||
__be32 cursor;
|
||||
__be32 curs_pos;
|
||||
__be32 diu_mode;
|
||||
__be32 bgnd;
|
||||
__be32 bgnd_wb;
|
||||
__be32 disp_size;
|
||||
__be32 wb_size;
|
||||
__be32 wb_mem_addr;
|
||||
__be32 hsyn_para;
|
||||
__be32 vsyn_para;
|
||||
__be32 syn_pol;
|
||||
__be32 thresholds;
|
||||
__be32 int_status;
|
||||
__be32 int_mask;
|
||||
__be32 colorbar[8];
|
||||
__be32 filling;
|
||||
__be32 plut;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
struct diu_addr {
|
||||
void *vaddr; /* Virtual address */
|
||||
u32 paddr; /* 32-bit physical address */
|
||||
unsigned int offset; /* Alignment offset */
|
||||
};
|
||||
|
||||
static struct fb_info info;
|
||||
|
||||
/*
|
||||
* Align to 64-bit(8-byte), 32-byte, etc.
|
||||
*/
|
||||
static int allocate_buf(struct diu_addr *buf, u32 size, u32 bytes_align)
|
||||
{
|
||||
u32 offset, ssize;
|
||||
u32 mask;
|
||||
|
||||
ssize = size + bytes_align;
|
||||
buf->vaddr = malloc(ssize);
|
||||
if (!buf->vaddr)
|
||||
return -1;
|
||||
|
||||
memset(buf->vaddr, 0, ssize);
|
||||
mask = bytes_align - 1;
|
||||
offset = (u32)buf->vaddr & mask;
|
||||
if (offset) {
|
||||
buf->offset = bytes_align - offset;
|
||||
buf->vaddr += offset;
|
||||
} else
|
||||
buf->offset = 0;
|
||||
|
||||
buf->paddr = virt_to_phys(buf->vaddr);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Allocate a framebuffer and an Area Descriptor that points to it. Both
|
||||
* are created in the same memory block. The Area Descriptor is updated to
|
||||
* point to the framebuffer memory. Memory is aligned as needed.
|
||||
*/
|
||||
static struct diu_ad *allocate_fb(unsigned int xres, unsigned int yres,
|
||||
unsigned int depth, char **fb)
|
||||
{
|
||||
unsigned long size = xres * yres * depth;
|
||||
struct diu_addr addr;
|
||||
struct diu_ad *ad;
|
||||
size_t ad_size = roundup(sizeof(struct diu_ad), 32);
|
||||
|
||||
/*
|
||||
* Allocate a memory block that holds the Area Descriptor and the
|
||||
* frame buffer right behind it. To keep the code simple, everything
|
||||
* is aligned on a 32-byte address.
|
||||
*/
|
||||
if (allocate_buf(&addr, ad_size + size, 32) < 0)
|
||||
return NULL;
|
||||
|
||||
ad = addr.vaddr;
|
||||
ad->addr = cpu_to_le32(addr.paddr + ad_size);
|
||||
ad->aoi_size = cpu_to_le32((yres << 16) | xres);
|
||||
ad->src_size_g_alpha = cpu_to_le32((yres << 12) | xres);
|
||||
ad->offset_xyi = 0;
|
||||
ad->offset_xyd = 0;
|
||||
|
||||
if (fb)
|
||||
*fb = addr.vaddr + ad_size;
|
||||
|
||||
return ad;
|
||||
}
|
||||
|
||||
int fsl_diu_init(u16 xres, u16 yres, u32 pixel_format, int gamma_fix)
|
||||
{
|
||||
struct fb_videomode *fsl_diu_mode_db;
|
||||
struct diu_ad *ad;
|
||||
struct diu *hw = (struct diu *)CONFIG_SYS_DIU_ADDR;
|
||||
u8 *gamma_table_base;
|
||||
unsigned int i, j;
|
||||
struct diu_ad *dummy_ad;
|
||||
struct diu_addr gamma;
|
||||
struct diu_addr cursor;
|
||||
|
||||
/* Convert the X,Y resolution pair into a single number */
|
||||
#define RESOLUTION(x, y) (((u32)(x) << 16) | (y))
|
||||
|
||||
switch (RESOLUTION(xres, yres)) {
|
||||
case RESOLUTION(800, 480):
|
||||
fsl_diu_mode_db = &fsl_diu_mode_800_480;
|
||||
break;
|
||||
case RESOLUTION(800, 600):
|
||||
fsl_diu_mode_db = &fsl_diu_mode_800_600;
|
||||
break;
|
||||
case RESOLUTION(1024, 768):
|
||||
fsl_diu_mode_db = &fsl_diu_mode_1024_768;
|
||||
break;
|
||||
case RESOLUTION(1280, 1024):
|
||||
fsl_diu_mode_db = &fsl_diu_mode_1280_1024;
|
||||
break;
|
||||
case RESOLUTION(1280, 720):
|
||||
fsl_diu_mode_db = &fsl_diu_mode_1280_720;
|
||||
break;
|
||||
case RESOLUTION(1920, 1080):
|
||||
fsl_diu_mode_db = &fsl_diu_mode_1920_1080;
|
||||
break;
|
||||
default:
|
||||
printf("DIU: Unsupported resolution %ux%u\n", xres, yres);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* The AD struct for the dummy framebuffer and the FB itself */
|
||||
dummy_ad = allocate_fb(2, 4, 4, NULL);
|
||||
if (!dummy_ad) {
|
||||
printf("DIU: Out of memory\n");
|
||||
return -1;
|
||||
}
|
||||
dummy_ad->pix_fmt = 0x88883316;
|
||||
|
||||
/* read mode info */
|
||||
info.var.xres = fsl_diu_mode_db->xres;
|
||||
info.var.yres = fsl_diu_mode_db->yres;
|
||||
info.var.bits_per_pixel = 32;
|
||||
info.var.pixclock = fsl_diu_mode_db->pixclock;
|
||||
info.var.left_margin = fsl_diu_mode_db->left_margin;
|
||||
info.var.right_margin = fsl_diu_mode_db->right_margin;
|
||||
info.var.upper_margin = fsl_diu_mode_db->upper_margin;
|
||||
info.var.lower_margin = fsl_diu_mode_db->lower_margin;
|
||||
info.var.hsync_len = fsl_diu_mode_db->hsync_len;
|
||||
info.var.vsync_len = fsl_diu_mode_db->vsync_len;
|
||||
info.var.sync = fsl_diu_mode_db->sync;
|
||||
info.var.vmode = fsl_diu_mode_db->vmode;
|
||||
info.fix.line_length = info.var.xres * info.var.bits_per_pixel / 8;
|
||||
|
||||
/* Memory allocation for framebuffer */
|
||||
info.screen_size =
|
||||
info.var.xres * info.var.yres * (info.var.bits_per_pixel / 8);
|
||||
ad = allocate_fb(info.var.xres, info.var.yres,
|
||||
info.var.bits_per_pixel / 8, &info.screen_base);
|
||||
if (!ad) {
|
||||
printf("DIU: Out of memory\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
ad->pix_fmt = pixel_format;
|
||||
|
||||
/* Disable chroma keying function */
|
||||
ad->ckmax_r = 0;
|
||||
ad->ckmax_g = 0;
|
||||
ad->ckmax_b = 0;
|
||||
|
||||
ad->ckmin_r = 255;
|
||||
ad->ckmin_g = 255;
|
||||
ad->ckmin_b = 255;
|
||||
|
||||
/* Initialize the gamma table */
|
||||
if (allocate_buf(&gamma, 256 * 3, 32) < 0) {
|
||||
printf("DIU: Out of memory\n");
|
||||
return -1;
|
||||
}
|
||||
gamma_table_base = gamma.vaddr;
|
||||
for (i = 0; i <= 2; i++)
|
||||
for (j = 0; j < 256; j++)
|
||||
*gamma_table_base++ = j;
|
||||
|
||||
if (gamma_fix == 1) { /* fix the gamma */
|
||||
gamma_table_base = gamma.vaddr;
|
||||
for (i = 0; i < 256 * 3; i++) {
|
||||
gamma_table_base[i] = (gamma_table_base[i] << 2)
|
||||
| ((gamma_table_base[i] >> 6) & 0x03);
|
||||
}
|
||||
}
|
||||
|
||||
/* Initialize the cursor */
|
||||
if (allocate_buf(&cursor, 32 * 32 * 2, 32) < 0) {
|
||||
printf("DIU: Can't alloc cursor data\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Program DIU registers */
|
||||
out_be32(&hw->diu_mode, 0); /* Temporarily disable the DIU */
|
||||
|
||||
out_be32(&hw->gamma, gamma.paddr);
|
||||
out_be32(&hw->cursor, cursor.paddr);
|
||||
out_be32(&hw->bgnd, 0x007F7F7F);
|
||||
out_be32(&hw->bgnd_wb, 0);
|
||||
out_be32(&hw->disp_size, info.var.yres << 16 | info.var.xres);
|
||||
out_be32(&hw->wb_size, 0);
|
||||
out_be32(&hw->wb_mem_addr, 0);
|
||||
out_be32(&hw->hsyn_para, info.var.left_margin << 22 |
|
||||
info.var.hsync_len << 11 |
|
||||
info.var.right_margin);
|
||||
|
||||
out_be32(&hw->vsyn_para, info.var.upper_margin << 22 |
|
||||
info.var.vsync_len << 11 |
|
||||
info.var.lower_margin);
|
||||
|
||||
out_be32(&hw->syn_pol, 0);
|
||||
out_be32(&hw->thresholds, 0x00037800);
|
||||
out_be32(&hw->int_status, 0);
|
||||
out_be32(&hw->int_mask, 0);
|
||||
out_be32(&hw->plut, 0x01F5F666);
|
||||
/* Pixel Clock configuration */
|
||||
diu_set_pixel_clock(info.var.pixclock);
|
||||
|
||||
/* Set the frame buffers */
|
||||
out_be32(&hw->desc[0], virt_to_phys(ad));
|
||||
out_be32(&hw->desc[1], virt_to_phys(dummy_ad));
|
||||
out_be32(&hw->desc[2], virt_to_phys(dummy_ad));
|
||||
|
||||
/* Enable the DIU, set display to all three planes */
|
||||
out_be32(&hw->diu_mode, 1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void *video_hw_init(void)
|
||||
{
|
||||
static GraphicDevice ctfb;
|
||||
const char *options;
|
||||
unsigned int depth = 0, freq = 0;
|
||||
|
||||
if (!video_get_video_mode(&ctfb.winSizeX, &ctfb.winSizeY, &depth, &freq,
|
||||
&options))
|
||||
return NULL;
|
||||
|
||||
/* Find the monitor port, which is a required option */
|
||||
if (!options)
|
||||
return NULL;
|
||||
if (strncmp(options, "monitor=", 8) != 0)
|
||||
return NULL;
|
||||
|
||||
if (platform_diu_init(ctfb.winSizeX, ctfb.winSizeY, options + 8) < 0)
|
||||
return NULL;
|
||||
|
||||
/* fill in Graphic device struct */
|
||||
sprintf(ctfb.modeIdent, "%ix%ix%i %ikHz %iHz",
|
||||
ctfb.winSizeX, ctfb.winSizeY, depth, 64, freq);
|
||||
|
||||
ctfb.frameAdrs = (unsigned int)info.screen_base;
|
||||
ctfb.plnSizeX = ctfb.winSizeX;
|
||||
ctfb.plnSizeY = ctfb.winSizeY;
|
||||
|
||||
ctfb.gdfBytesPP = 4;
|
||||
ctfb.gdfIndex = GDF_32BIT_X888RGB;
|
||||
|
||||
ctfb.isaBase = 0;
|
||||
ctfb.pciBase = 0;
|
||||
ctfb.memSize = info.screen_size;
|
||||
|
||||
/* Cursor Start Address */
|
||||
ctfb.dprBase = 0;
|
||||
ctfb.vprBase = 0;
|
||||
ctfb.cprBase = 0;
|
||||
|
||||
return &ctfb;
|
||||
}
|
||||
277
common/package/boot/uboot-ipq40xx/src/drivers/video/ipu.h
Normal file
277
common/package/boot/uboot-ipq40xx/src/drivers/video/ipu.h
Normal file
|
|
@ -0,0 +1,277 @@
|
|||
/*
|
||||
* Porting to u-boot:
|
||||
*
|
||||
* (C) Copyright 2010
|
||||
* Stefano Babic, DENX Software Engineering, sbabic@denx.de
|
||||
*
|
||||
* Linux IPU driver for MX51:
|
||||
*
|
||||
* (C) Copyright 2005-2010 Freescale Semiconductor, Inc.
|
||||
*
|
||||
* See file CREDITS for list of people who contributed to this
|
||||
* project.
|
||||
*
|
||||
* 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
|
||||
*/
|
||||
|
||||
#ifndef __ASM_ARCH_IPU_H__
|
||||
#define __ASM_ARCH_IPU_H__
|
||||
|
||||
#include <linux/types.h>
|
||||
#include <ipu_pixfmt.h>
|
||||
|
||||
#define IDMA_CHAN_INVALID 0xFF
|
||||
#define HIGH_RESOLUTION_WIDTH 1024
|
||||
|
||||
struct clk {
|
||||
const char *name;
|
||||
int id;
|
||||
/* Source clock this clk depends on */
|
||||
struct clk *parent;
|
||||
/* Secondary clock to enable/disable with this clock */
|
||||
struct clk *secondary;
|
||||
/* Current clock rate */
|
||||
unsigned long rate;
|
||||
/* Reference count of clock enable/disable */
|
||||
__s8 usecount;
|
||||
/* Register bit position for clock's enable/disable control. */
|
||||
u8 enable_shift;
|
||||
/* Register address for clock's enable/disable control. */
|
||||
void *enable_reg;
|
||||
u32 flags;
|
||||
/*
|
||||
* Function ptr to recalculate the clock's rate based on parent
|
||||
* clock's rate
|
||||
*/
|
||||
void (*recalc) (struct clk *);
|
||||
/*
|
||||
* Function ptr to set the clock to a new rate. The rate must match a
|
||||
* supported rate returned from round_rate. Leave blank if clock is not
|
||||
* programmable
|
||||
*/
|
||||
int (*set_rate) (struct clk *, unsigned long);
|
||||
/*
|
||||
* Function ptr to round the requested clock rate to the nearest
|
||||
* supported rate that is less than or equal to the requested rate.
|
||||
*/
|
||||
unsigned long (*round_rate) (struct clk *, unsigned long);
|
||||
/*
|
||||
* Function ptr to enable the clock. Leave blank if clock can not
|
||||
* be gated.
|
||||
*/
|
||||
int (*enable) (struct clk *);
|
||||
/*
|
||||
* Function ptr to disable the clock. Leave blank if clock can not
|
||||
* be gated.
|
||||
*/
|
||||
void (*disable) (struct clk *);
|
||||
/* Function ptr to set the parent clock of the clock. */
|
||||
int (*set_parent) (struct clk *, struct clk *);
|
||||
};
|
||||
|
||||
/*
|
||||
* Enumeration of Synchronous (Memory-less) panel types
|
||||
*/
|
||||
typedef enum {
|
||||
IPU_PANEL_SHARP_TFT,
|
||||
IPU_PANEL_TFT,
|
||||
} ipu_panel_t;
|
||||
|
||||
/*
|
||||
* IPU Driver channels definitions.
|
||||
* Note these are different from IDMA channels
|
||||
*/
|
||||
#define IPU_MAX_CH 32
|
||||
#define _MAKE_CHAN(num, v_in, g_in, a_in, out) \
|
||||
((num << 24) | (v_in << 18) | (g_in << 12) | (a_in << 6) | out)
|
||||
#define _MAKE_ALT_CHAN(ch) (ch | (IPU_MAX_CH << 24))
|
||||
#define IPU_CHAN_ID(ch) (ch >> 24)
|
||||
#define IPU_CHAN_ALT(ch) (ch & 0x02000000)
|
||||
#define IPU_CHAN_ALPHA_IN_DMA(ch) ((uint32_t) (ch >> 6) & 0x3F)
|
||||
#define IPU_CHAN_GRAPH_IN_DMA(ch) ((uint32_t) (ch >> 12) & 0x3F)
|
||||
#define IPU_CHAN_VIDEO_IN_DMA(ch) ((uint32_t) (ch >> 18) & 0x3F)
|
||||
#define IPU_CHAN_OUT_DMA(ch) ((uint32_t) (ch & 0x3F))
|
||||
#define NO_DMA 0x3F
|
||||
#define ALT 1
|
||||
|
||||
/*
|
||||
* Enumeration of IPU logical channels. An IPU logical channel is defined as a
|
||||
* combination of an input (memory to IPU), output (IPU to memory), and/or
|
||||
* secondary input IDMA channels and in some cases an Image Converter task.
|
||||
* Some channels consist of only an input or output.
|
||||
*/
|
||||
typedef enum {
|
||||
CHAN_NONE = -1,
|
||||
|
||||
MEM_DC_SYNC = _MAKE_CHAN(7, 28, NO_DMA, NO_DMA, NO_DMA),
|
||||
MEM_DC_ASYNC = _MAKE_CHAN(8, 41, NO_DMA, NO_DMA, NO_DMA),
|
||||
MEM_BG_SYNC = _MAKE_CHAN(9, 23, NO_DMA, 51, NO_DMA),
|
||||
MEM_FG_SYNC = _MAKE_CHAN(10, 27, NO_DMA, 31, NO_DMA),
|
||||
|
||||
MEM_BG_ASYNC0 = _MAKE_CHAN(11, 24, NO_DMA, 52, NO_DMA),
|
||||
MEM_FG_ASYNC0 = _MAKE_CHAN(12, 29, NO_DMA, 33, NO_DMA),
|
||||
MEM_BG_ASYNC1 = _MAKE_ALT_CHAN(MEM_BG_ASYNC0),
|
||||
MEM_FG_ASYNC1 = _MAKE_ALT_CHAN(MEM_FG_ASYNC0),
|
||||
|
||||
DIRECT_ASYNC0 = _MAKE_CHAN(13, NO_DMA, NO_DMA, NO_DMA, NO_DMA),
|
||||
DIRECT_ASYNC1 = _MAKE_CHAN(14, NO_DMA, NO_DMA, NO_DMA, NO_DMA),
|
||||
|
||||
} ipu_channel_t;
|
||||
|
||||
/*
|
||||
* Enumeration of types of buffers for a logical channel.
|
||||
*/
|
||||
typedef enum {
|
||||
IPU_OUTPUT_BUFFER = 0, /*< Buffer for output from IPU */
|
||||
IPU_ALPHA_IN_BUFFER = 1, /*< Buffer for input to IPU */
|
||||
IPU_GRAPH_IN_BUFFER = 2, /*< Buffer for input to IPU */
|
||||
IPU_VIDEO_IN_BUFFER = 3, /*< Buffer for input to IPU */
|
||||
IPU_INPUT_BUFFER = IPU_VIDEO_IN_BUFFER,
|
||||
IPU_SEC_INPUT_BUFFER = IPU_GRAPH_IN_BUFFER,
|
||||
} ipu_buffer_t;
|
||||
|
||||
#define IPU_PANEL_SERIAL 1
|
||||
#define IPU_PANEL_PARALLEL 2
|
||||
|
||||
struct ipu_channel {
|
||||
u8 video_in_dma;
|
||||
u8 alpha_in_dma;
|
||||
u8 graph_in_dma;
|
||||
u8 out_dma;
|
||||
};
|
||||
|
||||
enum ipu_dmfc_type {
|
||||
DMFC_NORMAL = 0,
|
||||
DMFC_HIGH_RESOLUTION_DC,
|
||||
DMFC_HIGH_RESOLUTION_DP,
|
||||
DMFC_HIGH_RESOLUTION_ONLY_DP,
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* Union of initialization parameters for a logical channel.
|
||||
*/
|
||||
typedef union {
|
||||
struct {
|
||||
uint32_t di;
|
||||
unsigned char interlaced;
|
||||
} mem_dc_sync;
|
||||
struct {
|
||||
uint32_t temp;
|
||||
} mem_sdc_fg;
|
||||
struct {
|
||||
uint32_t di;
|
||||
unsigned char interlaced;
|
||||
uint32_t in_pixel_fmt;
|
||||
uint32_t out_pixel_fmt;
|
||||
unsigned char alpha_chan_en;
|
||||
} mem_dp_bg_sync;
|
||||
struct {
|
||||
uint32_t temp;
|
||||
} mem_sdc_bg;
|
||||
struct {
|
||||
uint32_t di;
|
||||
unsigned char interlaced;
|
||||
uint32_t in_pixel_fmt;
|
||||
uint32_t out_pixel_fmt;
|
||||
unsigned char alpha_chan_en;
|
||||
} mem_dp_fg_sync;
|
||||
} ipu_channel_params_t;
|
||||
|
||||
/*
|
||||
* Bitfield of Display Interface signal polarities.
|
||||
*/
|
||||
typedef struct {
|
||||
unsigned datamask_en:1;
|
||||
unsigned ext_clk:1;
|
||||
unsigned interlaced:1;
|
||||
unsigned odd_field_first:1;
|
||||
unsigned clksel_en:1;
|
||||
unsigned clkidle_en:1;
|
||||
unsigned data_pol:1; /* true = inverted */
|
||||
unsigned clk_pol:1; /* true = rising edge */
|
||||
unsigned enable_pol:1;
|
||||
unsigned Hsync_pol:1; /* true = active high */
|
||||
unsigned Vsync_pol:1;
|
||||
} ipu_di_signal_cfg_t;
|
||||
|
||||
typedef enum {
|
||||
RGB,
|
||||
YCbCr,
|
||||
YUV
|
||||
} ipu_color_space_t;
|
||||
|
||||
/* Common IPU API */
|
||||
int32_t ipu_init_channel(ipu_channel_t channel, ipu_channel_params_t *params);
|
||||
void ipu_uninit_channel(ipu_channel_t channel);
|
||||
|
||||
int32_t ipu_init_channel_buffer(ipu_channel_t channel, ipu_buffer_t type,
|
||||
uint32_t pixel_fmt,
|
||||
uint16_t width, uint16_t height,
|
||||
uint32_t stride,
|
||||
dma_addr_t phyaddr_0, dma_addr_t phyaddr_1,
|
||||
uint32_t u_offset, uint32_t v_offset);
|
||||
|
||||
int32_t ipu_update_channel_buffer(ipu_channel_t channel, ipu_buffer_t type,
|
||||
uint32_t bufNum, dma_addr_t phyaddr);
|
||||
|
||||
int32_t ipu_is_channel_busy(ipu_channel_t channel);
|
||||
void ipu_clear_buffer_ready(ipu_channel_t channel, ipu_buffer_t type,
|
||||
uint32_t bufNum);
|
||||
int32_t ipu_enable_channel(ipu_channel_t channel);
|
||||
int32_t ipu_disable_channel(ipu_channel_t channel);
|
||||
|
||||
int32_t ipu_init_sync_panel(int disp,
|
||||
uint32_t pixel_clk,
|
||||
uint16_t width, uint16_t height,
|
||||
uint32_t pixel_fmt,
|
||||
uint16_t h_start_width, uint16_t h_sync_width,
|
||||
uint16_t h_end_width, uint16_t v_start_width,
|
||||
uint16_t v_sync_width, uint16_t v_end_width,
|
||||
uint32_t v_to_h_sync, ipu_di_signal_cfg_t sig);
|
||||
|
||||
int32_t ipu_disp_set_global_alpha(ipu_channel_t channel, unsigned char enable,
|
||||
uint8_t alpha);
|
||||
int32_t ipu_disp_set_color_key(ipu_channel_t channel, unsigned char enable,
|
||||
uint32_t colorKey);
|
||||
|
||||
uint32_t bytes_per_pixel(uint32_t fmt);
|
||||
|
||||
void clk_enable(struct clk *clk);
|
||||
void clk_disable(struct clk *clk);
|
||||
u32 clk_get_rate(struct clk *clk);
|
||||
int clk_set_rate(struct clk *clk, unsigned long rate);
|
||||
long clk_round_rate(struct clk *clk, unsigned long rate);
|
||||
int clk_set_parent(struct clk *clk, struct clk *parent);
|
||||
int clk_get_usecount(struct clk *clk);
|
||||
struct clk *clk_get_parent(struct clk *clk);
|
||||
|
||||
void ipu_dump_registers(void);
|
||||
int ipu_probe(void);
|
||||
|
||||
void ipu_dmfc_init(int dmfc_type, int first);
|
||||
void ipu_init_dc_mappings(void);
|
||||
void ipu_dmfc_set_wait4eot(int dma_chan, int width);
|
||||
void ipu_dc_init(int dc_chan, int di, unsigned char interlaced);
|
||||
void ipu_dc_uninit(int dc_chan);
|
||||
void ipu_dp_dc_enable(ipu_channel_t channel);
|
||||
int ipu_dp_init(ipu_channel_t channel, uint32_t in_pixel_fmt,
|
||||
uint32_t out_pixel_fmt);
|
||||
void ipu_dp_uninit(ipu_channel_t channel);
|
||||
void ipu_dp_dc_disable(ipu_channel_t channel, unsigned char swap);
|
||||
ipu_color_space_t format_to_colorspace(uint32_t fmt);
|
||||
|
||||
#endif
|
||||
1196
common/package/boot/uboot-ipq40xx/src/drivers/video/ipu_common.c
Normal file
1196
common/package/boot/uboot-ipq40xx/src/drivers/video/ipu_common.c
Normal file
File diff suppressed because it is too large
Load diff
1351
common/package/boot/uboot-ipq40xx/src/drivers/video/ipu_disp.c
Normal file
1351
common/package/boot/uboot-ipq40xx/src/drivers/video/ipu_disp.c
Normal file
File diff suppressed because it is too large
Load diff
428
common/package/boot/uboot-ipq40xx/src/drivers/video/ipu_regs.h
Normal file
428
common/package/boot/uboot-ipq40xx/src/drivers/video/ipu_regs.h
Normal file
|
|
@ -0,0 +1,428 @@
|
|||
/*
|
||||
* Porting to u-boot:
|
||||
*
|
||||
* (C) Copyright 2010
|
||||
* Stefano Babic, DENX Software Engineering, sbabic@denx.de
|
||||
*
|
||||
* Linux IPU driver for MX51:
|
||||
*
|
||||
* (C) Copyright 2005-2009 Freescale Semiconductor, Inc.
|
||||
*
|
||||
* See file CREDITS for list of people who contributed to this
|
||||
* project.
|
||||
*
|
||||
* 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
|
||||
*/
|
||||
|
||||
#ifndef __IPU_REGS_INCLUDED__
|
||||
#define __IPU_REGS_INCLUDED__
|
||||
|
||||
#define IPU_DISP0_BASE 0x00000000
|
||||
#define IPU_MCU_T_DEFAULT 8
|
||||
#define IPU_DISP1_BASE (IPU_MCU_T_DEFAULT << 25)
|
||||
#define IPU_CM_REG_BASE 0x00000000
|
||||
#define IPU_STAT_REG_BASE 0x00000200
|
||||
#define IPU_IDMAC_REG_BASE 0x00008000
|
||||
#define IPU_ISP_REG_BASE 0x00010000
|
||||
#define IPU_DP_REG_BASE 0x00018000
|
||||
#define IPU_IC_REG_BASE 0x00020000
|
||||
#define IPU_IRT_REG_BASE 0x00028000
|
||||
#define IPU_CSI0_REG_BASE 0x00030000
|
||||
#define IPU_CSI1_REG_BASE 0x00038000
|
||||
#define IPU_DI0_REG_BASE 0x00040000
|
||||
#define IPU_DI1_REG_BASE 0x00048000
|
||||
#define IPU_SMFC_REG_BASE 0x00050000
|
||||
#define IPU_DC_REG_BASE 0x00058000
|
||||
#define IPU_DMFC_REG_BASE 0x00060000
|
||||
#define IPU_VDI_REG_BASE 0x00680000
|
||||
#if defined(CONFIG_MX51) || defined(CONFIG_MX53)
|
||||
#define IPU_CPMEM_REG_BASE 0x01000000
|
||||
#define IPU_LUT_REG_BASE 0x01020000
|
||||
#define IPU_SRM_REG_BASE 0x01040000
|
||||
#define IPU_TPM_REG_BASE 0x01060000
|
||||
#define IPU_DC_TMPL_REG_BASE 0x01080000
|
||||
#define IPU_ISP_TBPR_REG_BASE 0x010C0000
|
||||
#elif defined(CONFIG_MX6Q)
|
||||
#define IPU_CPMEM_REG_BASE 0x00100000
|
||||
#define IPU_LUT_REG_BASE 0x00120000
|
||||
#define IPU_SRM_REG_BASE 0x00140000
|
||||
#define IPU_TPM_REG_BASE 0x00160000
|
||||
#define IPU_DC_TMPL_REG_BASE 0x00180000
|
||||
#define IPU_ISP_TBPR_REG_BASE 0x001C0000
|
||||
#endif
|
||||
|
||||
#define IPU_CTRL_BASE_ADDR (IPU_SOC_BASE_ADDR + IPU_SOC_OFFSET)
|
||||
|
||||
extern u32 *ipu_dc_tmpl_reg;
|
||||
|
||||
#define DC_EVT_NF 0
|
||||
#define DC_EVT_NL 1
|
||||
#define DC_EVT_EOF 2
|
||||
#define DC_EVT_NFIELD 3
|
||||
#define DC_EVT_EOL 4
|
||||
#define DC_EVT_EOFIELD 5
|
||||
#define DC_EVT_NEW_ADDR 6
|
||||
#define DC_EVT_NEW_CHAN 7
|
||||
#define DC_EVT_NEW_DATA 8
|
||||
|
||||
#define DC_EVT_NEW_ADDR_W_0 0
|
||||
#define DC_EVT_NEW_ADDR_W_1 1
|
||||
#define DC_EVT_NEW_CHAN_W_0 2
|
||||
#define DC_EVT_NEW_CHAN_W_1 3
|
||||
#define DC_EVT_NEW_DATA_W_0 4
|
||||
#define DC_EVT_NEW_DATA_W_1 5
|
||||
#define DC_EVT_NEW_ADDR_R_0 6
|
||||
#define DC_EVT_NEW_ADDR_R_1 7
|
||||
#define DC_EVT_NEW_CHAN_R_0 8
|
||||
#define DC_EVT_NEW_CHAN_R_1 9
|
||||
#define DC_EVT_NEW_DATA_R_0 10
|
||||
#define DC_EVT_NEW_DATA_R_1 11
|
||||
|
||||
/* Software reset for ipu */
|
||||
#define SW_IPU_RST 8
|
||||
|
||||
enum {
|
||||
IPU_CONF_DP_EN = 0x00000020,
|
||||
IPU_CONF_DI0_EN = 0x00000040,
|
||||
IPU_CONF_DI1_EN = 0x00000080,
|
||||
IPU_CONF_DMFC_EN = 0x00000400,
|
||||
IPU_CONF_DC_EN = 0x00000200,
|
||||
|
||||
DI0_COUNTER_RELEASE = 0x01000000,
|
||||
DI1_COUNTER_RELEASE = 0x02000000,
|
||||
|
||||
DI_DW_GEN_ACCESS_SIZE_OFFSET = 24,
|
||||
DI_DW_GEN_COMPONENT_SIZE_OFFSET = 16,
|
||||
|
||||
DI_GEN_DI_CLK_EXT = 0x100000,
|
||||
DI_GEN_POLARITY_1 = 0x00000001,
|
||||
DI_GEN_POLARITY_2 = 0x00000002,
|
||||
DI_GEN_POLARITY_3 = 0x00000004,
|
||||
DI_GEN_POLARITY_4 = 0x00000008,
|
||||
DI_GEN_POLARITY_5 = 0x00000010,
|
||||
DI_GEN_POLARITY_6 = 0x00000020,
|
||||
DI_GEN_POLARITY_7 = 0x00000040,
|
||||
DI_GEN_POLARITY_8 = 0x00000080,
|
||||
DI_GEN_POL_CLK = 0x20000,
|
||||
|
||||
DI_POL_DRDY_DATA_POLARITY = 0x00000080,
|
||||
DI_POL_DRDY_POLARITY_15 = 0x00000010,
|
||||
DI_VSYNC_SEL_OFFSET = 13,
|
||||
|
||||
DC_WR_CH_CONF_FIELD_MODE = 0x00000200,
|
||||
DC_WR_CH_CONF_PROG_TYPE_OFFSET = 5,
|
||||
DC_WR_CH_CONF_PROG_TYPE_MASK = 0x000000E0,
|
||||
DC_WR_CH_CONF_PROG_DI_ID = 0x00000004,
|
||||
DC_WR_CH_CONF_PROG_DISP_ID_OFFSET = 3,
|
||||
DC_WR_CH_CONF_PROG_DISP_ID_MASK = 0x00000018,
|
||||
|
||||
DP_COM_CONF_FG_EN = 0x00000001,
|
||||
DP_COM_CONF_GWSEL = 0x00000002,
|
||||
DP_COM_CONF_GWAM = 0x00000004,
|
||||
DP_COM_CONF_GWCKE = 0x00000008,
|
||||
DP_COM_CONF_CSC_DEF_MASK = 0x00000300,
|
||||
DP_COM_CONF_CSC_DEF_OFFSET = 8,
|
||||
DP_COM_CONF_CSC_DEF_FG = 0x00000300,
|
||||
DP_COM_CONF_CSC_DEF_BG = 0x00000200,
|
||||
DP_COM_CONF_CSC_DEF_BOTH = 0x00000100,
|
||||
DP_COM_CONF_GAMMA_EN = 0x00001000,
|
||||
DP_COM_CONF_GAMMA_YUV_EN = 0x00002000,
|
||||
};
|
||||
|
||||
enum di_pins {
|
||||
DI_PIN11 = 0,
|
||||
DI_PIN12 = 1,
|
||||
DI_PIN13 = 2,
|
||||
DI_PIN14 = 3,
|
||||
DI_PIN15 = 4,
|
||||
DI_PIN16 = 5,
|
||||
DI_PIN17 = 6,
|
||||
DI_PIN_CS = 7,
|
||||
|
||||
DI_PIN_SER_CLK = 0,
|
||||
DI_PIN_SER_RS = 1,
|
||||
};
|
||||
|
||||
enum di_sync_wave {
|
||||
DI_SYNC_NONE = -1,
|
||||
DI_SYNC_CLK = 0,
|
||||
DI_SYNC_INT_HSYNC = 1,
|
||||
DI_SYNC_HSYNC = 2,
|
||||
DI_SYNC_VSYNC = 3,
|
||||
DI_SYNC_DE = 5,
|
||||
};
|
||||
|
||||
struct ipu_cm {
|
||||
u32 conf;
|
||||
u32 sisg_ctrl0;
|
||||
u32 sisg_ctrl1;
|
||||
u32 sisg_set[6];
|
||||
u32 sisg_clear[6];
|
||||
u32 int_ctrl[15];
|
||||
u32 sdma_event[10];
|
||||
u32 srm_pri1;
|
||||
u32 srm_pri2;
|
||||
u32 fs_proc_flow[3];
|
||||
u32 fs_disp_flow[2];
|
||||
u32 skip;
|
||||
u32 disp_alt_conf;
|
||||
u32 disp_gen;
|
||||
u32 disp_alt[4];
|
||||
u32 snoop;
|
||||
u32 mem_rst;
|
||||
u32 pm;
|
||||
u32 gpr;
|
||||
u32 reserved0[26];
|
||||
u32 ch_db_mode_sel[2];
|
||||
u32 reserved1[16];
|
||||
u32 alt_ch_db_mode_sel[2];
|
||||
u32 reserved2[2];
|
||||
u32 ch_trb_mode_sel[2];
|
||||
};
|
||||
|
||||
struct ipu_idmac {
|
||||
u32 conf;
|
||||
u32 ch_en[2];
|
||||
u32 sep_alpha;
|
||||
u32 alt_sep_alpha;
|
||||
u32 ch_pri[2];
|
||||
u32 wm_en[2];
|
||||
u32 lock_en[2];
|
||||
u32 sub_addr[5];
|
||||
u32 bndm_en[2];
|
||||
u32 sc_cord[2];
|
||||
u32 reserved[45];
|
||||
u32 ch_busy[2];
|
||||
};
|
||||
|
||||
struct ipu_com_async {
|
||||
u32 com_conf_async;
|
||||
u32 graph_wind_ctrl_async;
|
||||
u32 fg_pos_async;
|
||||
u32 cur_pos_async;
|
||||
u32 cur_map_async;
|
||||
u32 gamma_c_async[8];
|
||||
u32 gamma_s_async[4];
|
||||
u32 dp_csca_async[4];
|
||||
u32 dp_csc_async[2];
|
||||
};
|
||||
|
||||
struct ipu_dp {
|
||||
u32 com_conf_sync;
|
||||
u32 graph_wind_ctrl_sync;
|
||||
u32 fg_pos_sync;
|
||||
u32 cur_pos_sync;
|
||||
u32 cur_map_sync;
|
||||
u32 gamma_c_sync[8];
|
||||
u32 gamma_s_sync[4];
|
||||
u32 csca_sync[4];
|
||||
u32 csc_sync[2];
|
||||
u32 cur_pos_alt;
|
||||
struct ipu_com_async async[2];
|
||||
};
|
||||
|
||||
struct ipu_di {
|
||||
u32 general;
|
||||
u32 bs_clkgen0;
|
||||
u32 bs_clkgen1;
|
||||
u32 sw_gen0[9];
|
||||
u32 sw_gen1[9];
|
||||
u32 sync_as;
|
||||
u32 dw_gen[12];
|
||||
u32 dw_set[48];
|
||||
u32 stp_rep[4];
|
||||
u32 stp_rep9;
|
||||
u32 ser_conf;
|
||||
u32 ssc;
|
||||
u32 pol;
|
||||
u32 aw0;
|
||||
u32 aw1;
|
||||
u32 scr_conf;
|
||||
u32 stat;
|
||||
};
|
||||
|
||||
struct ipu_stat {
|
||||
u32 int_stat[15];
|
||||
u32 cur_buf[2];
|
||||
u32 alt_cur_buf_0;
|
||||
u32 alt_cur_buf_1;
|
||||
u32 srm_stat;
|
||||
u32 proc_task_stat;
|
||||
u32 disp_task_stat;
|
||||
u32 triple_cur_buf[4];
|
||||
u32 ch_buf0_rdy[2];
|
||||
u32 ch_buf1_rdy[2];
|
||||
u32 alt_ch_buf0_rdy[2];
|
||||
u32 alt_ch_buf1_rdy[2];
|
||||
u32 ch_buf2_rdy[2];
|
||||
};
|
||||
|
||||
struct ipu_dc_ch {
|
||||
u32 wr_ch_conf;
|
||||
u32 wr_ch_addr;
|
||||
u32 rl[5];
|
||||
};
|
||||
|
||||
struct ipu_dc {
|
||||
struct ipu_dc_ch dc_ch0_1_2[3];
|
||||
u32 cmd_ch_conf_3;
|
||||
u32 cmd_ch_conf_4;
|
||||
struct ipu_dc_ch dc_ch5_6[2];
|
||||
struct ipu_dc_ch dc_ch8;
|
||||
u32 rl6_ch_8;
|
||||
struct ipu_dc_ch dc_ch9;
|
||||
u32 rl6_ch_9;
|
||||
u32 gen;
|
||||
u32 disp_conf1[4];
|
||||
u32 disp_conf2[4];
|
||||
u32 di0_conf[2];
|
||||
u32 di1_conf[2];
|
||||
u32 dc_map_ptr[15];
|
||||
u32 dc_map_val[12];
|
||||
u32 udge[16];
|
||||
u32 lla[2];
|
||||
u32 r_lla[2];
|
||||
u32 wr_ch_addr_5_alt;
|
||||
u32 stat;
|
||||
};
|
||||
|
||||
struct ipu_dmfc {
|
||||
u32 rd_chan;
|
||||
u32 wr_chan;
|
||||
u32 wr_chan_def;
|
||||
u32 dp_chan;
|
||||
u32 dp_chan_def;
|
||||
u32 general[2];
|
||||
u32 ic_ctrl;
|
||||
u32 wr_chan_alt;
|
||||
u32 wr_chan_def_alt;
|
||||
u32 general1_alt;
|
||||
u32 stat;
|
||||
};
|
||||
|
||||
#define IPU_CM_REG ((struct ipu_cm *)(IPU_CTRL_BASE_ADDR + \
|
||||
IPU_CM_REG_BASE))
|
||||
#define IPU_CONF (&IPU_CM_REG->conf)
|
||||
#define IPU_SRM_PRI1 (&IPU_CM_REG->srm_pri1)
|
||||
#define IPU_SRM_PRI2 (&IPU_CM_REG->srm_pri2)
|
||||
#define IPU_FS_PROC_FLOW1 (&IPU_CM_REG->fs_proc_flow[0])
|
||||
#define IPU_FS_PROC_FLOW2 (&IPU_CM_REG->fs_proc_flow[1])
|
||||
#define IPU_FS_PROC_FLOW3 (&IPU_CM_REG->fs_proc_flow[2])
|
||||
#define IPU_FS_DISP_FLOW1 (&IPU_CM_REG->fs_disp_flow[0])
|
||||
#define IPU_DISP_GEN (&IPU_CM_REG->disp_gen)
|
||||
#define IPU_MEM_RST (&IPU_CM_REG->mem_rst)
|
||||
#define IPU_GPR (&IPU_CM_REG->gpr)
|
||||
#define IPU_CHA_DB_MODE_SEL(ch) (&IPU_CM_REG->ch_db_mode_sel[ch / 32])
|
||||
|
||||
#define IPU_STAT ((struct ipu_stat *)(IPU_CTRL_BASE_ADDR + \
|
||||
IPU_STAT_REG_BASE))
|
||||
#define IPU_CHA_CUR_BUF(ch) (&IPU_STAT->cur_buf[ch / 32])
|
||||
#define IPU_CHA_BUF0_RDY(ch) (&IPU_STAT->ch_buf0_rdy[ch / 32])
|
||||
#define IPU_CHA_BUF1_RDY(ch) (&IPU_STAT->ch_buf1_rdy[ch / 32])
|
||||
|
||||
#define IPU_INT_CTRL(n) (&IPU_CM_REG->int_ctrl[(n) - 1])
|
||||
|
||||
#define IDMAC_REG ((struct ipu_idmac *)(IPU_CTRL_BASE_ADDR + \
|
||||
IPU_IDMAC_REG_BASE))
|
||||
#define IDMAC_CONF (&IDMAC_REG->conf)
|
||||
#define IDMAC_CHA_EN(ch) (&IDMAC_REG->ch_en[ch / 32])
|
||||
#define IDMAC_CHA_PRI(ch) (&IDMAC_REG->ch_pri[ch / 32])
|
||||
|
||||
#define DI_REG(di) ((struct ipu_di *)(IPU_CTRL_BASE_ADDR + \
|
||||
((di == 1) ? IPU_DI1_REG_BASE : \
|
||||
IPU_DI0_REG_BASE)))
|
||||
#define DI_GENERAL(di) (&DI_REG(di)->general)
|
||||
#define DI_BS_CLKGEN0(di) (&DI_REG(di)->bs_clkgen0)
|
||||
#define DI_BS_CLKGEN1(di) (&DI_REG(di)->bs_clkgen1)
|
||||
|
||||
#define DI_SW_GEN0(di, gen) (&DI_REG(di)->sw_gen0[gen - 1])
|
||||
#define DI_SW_GEN1(di, gen) (&DI_REG(di)->sw_gen1[gen - 1])
|
||||
#define DI_STP_REP(di, gen) (&DI_REG(di)->stp_rep[(gen - 1) / 2])
|
||||
#define DI_SYNC_AS_GEN(di) (&DI_REG(di)->sync_as)
|
||||
#define DI_DW_GEN(di, gen) (&DI_REG(di)->dw_gen[gen])
|
||||
#define DI_DW_SET(di, gen, set) (&DI_REG(di)->dw_set[gen + 12 * set])
|
||||
#define DI_POL(di) (&DI_REG(di)->pol)
|
||||
#define DI_SCR_CONF(di) (&DI_REG(di)->scr_conf)
|
||||
|
||||
#define DMFC_REG ((struct ipu_dmfc *)(IPU_CTRL_BASE_ADDR + \
|
||||
IPU_DMFC_REG_BASE))
|
||||
#define DMFC_WR_CHAN (&DMFC_REG->wr_chan)
|
||||
#define DMFC_WR_CHAN_DEF (&DMFC_REG->wr_chan_def)
|
||||
#define DMFC_DP_CHAN (&DMFC_REG->dp_chan)
|
||||
#define DMFC_DP_CHAN_DEF (&DMFC_REG->dp_chan_def)
|
||||
#define DMFC_GENERAL1 (&DMFC_REG->general[0])
|
||||
#define DMFC_IC_CTRL (&DMFC_REG->ic_ctrl)
|
||||
|
||||
|
||||
#define DC_REG ((struct ipu_dc *)(IPU_CTRL_BASE_ADDR + \
|
||||
IPU_DC_REG_BASE))
|
||||
#define DC_MAP_CONF_PTR(n) (&DC_REG->dc_map_ptr[n / 2])
|
||||
#define DC_MAP_CONF_VAL(n) (&DC_REG->dc_map_val[n / 2])
|
||||
|
||||
|
||||
static inline struct ipu_dc_ch *dc_ch_offset(int ch)
|
||||
{
|
||||
switch (ch) {
|
||||
case 0:
|
||||
case 1:
|
||||
case 2:
|
||||
return &DC_REG->dc_ch0_1_2[ch];
|
||||
case 5:
|
||||
case 6:
|
||||
return &DC_REG->dc_ch5_6[ch - 5];
|
||||
case 8:
|
||||
return &DC_REG->dc_ch8;
|
||||
case 9:
|
||||
return &DC_REG->dc_ch9;
|
||||
default:
|
||||
printf("%s: invalid channel %d\n", __func__, ch);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#define DC_RL_CH(ch, evt) (&dc_ch_offset(ch)->rl[evt / 2])
|
||||
|
||||
#define DC_WR_CH_CONF(ch) (&dc_ch_offset(ch)->wr_ch_conf)
|
||||
#define DC_WR_CH_ADDR(ch) (&dc_ch_offset(ch)->wr_ch_addr)
|
||||
|
||||
#define DC_WR_CH_CONF_1 DC_WR_CH_CONF(1)
|
||||
#define DC_WR_CH_CONF_5 DC_WR_CH_CONF(5)
|
||||
|
||||
#define DC_GEN (&DC_REG->gen)
|
||||
#define DC_DISP_CONF2(disp) (&DC_REG->disp_conf2[disp])
|
||||
#define DC_STAT (&DC_REG->stat)
|
||||
|
||||
#define DP_SYNC 0
|
||||
#define DP_ASYNC0 0x60
|
||||
#define DP_ASYNC1 0xBC
|
||||
|
||||
#define DP_REG ((struct ipu_dp *)(IPU_CTRL_BASE_ADDR + \
|
||||
IPU_DP_REG_BASE))
|
||||
#define DP_COM_CONF() (&DP_REG->com_conf_sync)
|
||||
#define DP_GRAPH_WIND_CTRL() (&DP_REG->graph_wind_ctrl_sync)
|
||||
#define DP_CSC_A_0() (&DP_REG->csca_sync[0])
|
||||
#define DP_CSC_A_1() (&DP_REG->csca_sync[1])
|
||||
#define DP_CSC_A_2() (&DP_REG->csca_sync[2])
|
||||
#define DP_CSC_A_3() (&DP_REG->csca_sync[3])
|
||||
|
||||
#define DP_CSC_0() (&DP_REG->csc_sync[0])
|
||||
#define DP_CSC_1() (&DP_REG->csc_sync[1])
|
||||
|
||||
/* DC template opcodes */
|
||||
#define WROD(lf) (0x18 | (lf << 1))
|
||||
|
||||
#endif
|
||||
500
common/package/boot/uboot-ipq40xx/src/drivers/video/mb862xx.c
Normal file
500
common/package/boot/uboot-ipq40xx/src/drivers/video/mb862xx.c
Normal file
|
|
@ -0,0 +1,500 @@
|
|||
/*
|
||||
* (C) Copyright 2007
|
||||
* DENX Software Engineering, Anatolij Gustschin, agust@denx.de
|
||||
*
|
||||
* See file CREDITS for list of people who contributed to this
|
||||
* project.
|
||||
*
|
||||
* 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
|
||||
*/
|
||||
|
||||
/*
|
||||
* mb862xx.c - Graphic interface for Fujitsu CoralP/Lime
|
||||
* PCI and video mode code was derived from smiLynxEM driver.
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
|
||||
#include <asm/io.h>
|
||||
#include <pci.h>
|
||||
#include <video_fb.h>
|
||||
#include "videomodes.h"
|
||||
#include <mb862xx.h>
|
||||
|
||||
#if defined(CONFIG_POST)
|
||||
#include <post.h>
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Graphic Device
|
||||
*/
|
||||
GraphicDevice mb862xx;
|
||||
|
||||
/*
|
||||
* 32MB external RAM - 256K Chip MMIO = 0x1FC0000 ;
|
||||
*/
|
||||
#define VIDEO_MEM_SIZE 0x01FC0000
|
||||
|
||||
#if defined(CONFIG_PCI)
|
||||
#if defined(CONFIG_VIDEO_CORALP)
|
||||
|
||||
static struct pci_device_id supported[] = {
|
||||
{ PCI_VENDOR_ID_FUJITSU, PCI_DEVICE_ID_CORAL_P },
|
||||
{ PCI_VENDOR_ID_FUJITSU, PCI_DEVICE_ID_CORAL_PA },
|
||||
{ }
|
||||
};
|
||||
|
||||
/* Internal clock frequency divider table, index is mode number */
|
||||
unsigned int fr_div[] = { 0x00000f00, 0x00000900, 0x00000500 };
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_VIDEO_CORALP)
|
||||
#define rd_io in32r
|
||||
#define wr_io out32r
|
||||
#else
|
||||
#define rd_io(addr) in_be32((volatile unsigned *)(addr))
|
||||
#define wr_io(addr, val) out_be32((volatile unsigned *)(addr), (val))
|
||||
#endif
|
||||
|
||||
#define HOST_RD_REG(off) rd_io((dev->frameAdrs + GC_HOST_BASE + (off)))
|
||||
#define HOST_WR_REG(off, val) wr_io((dev->frameAdrs + GC_HOST_BASE + (off)), \
|
||||
(val))
|
||||
#define DISP_RD_REG(off) rd_io((dev->frameAdrs + GC_DISP_BASE + (off)))
|
||||
#define DISP_WR_REG(off, val) wr_io((dev->frameAdrs + GC_DISP_BASE + (off)), \
|
||||
(val))
|
||||
#define DE_RD_REG(off) rd_io((dev->dprBase + (off)))
|
||||
#define DE_WR_REG(off, val) wr_io((dev->dprBase + (off)), (val))
|
||||
|
||||
#if defined(CONFIG_VIDEO_CORALP)
|
||||
#define DE_WR_FIFO(val) wr_io((dev->dprBase + (GC_GEO_FIFO)), (val))
|
||||
#else
|
||||
#define DE_WR_FIFO(val) wr_io((dev->dprBase + (GC_FIFO)), (val))
|
||||
#endif
|
||||
|
||||
#define L0PAL_WR_REG(idx, val) wr_io((dev->frameAdrs + \
|
||||
(GC_DISP_BASE | GC_L0PAL0) + \
|
||||
((idx) << 2)), (val))
|
||||
|
||||
#if defined(CONFIG_VIDEO_MB862xx_ACCEL)
|
||||
static void gdc_sw_reset (void)
|
||||
{
|
||||
GraphicDevice *dev = &mb862xx;
|
||||
|
||||
HOST_WR_REG (GC_SRST, 0x1);
|
||||
udelay (500);
|
||||
video_hw_init ();
|
||||
}
|
||||
|
||||
|
||||
static void de_wait (void)
|
||||
{
|
||||
GraphicDevice *dev = &mb862xx;
|
||||
int lc = 0x10000;
|
||||
|
||||
/*
|
||||
* Sync with software writes to framebuffer,
|
||||
* try to reset if engine locked
|
||||
*/
|
||||
while (DE_RD_REG (GC_CTR) & 0x00000131)
|
||||
if (lc-- < 0) {
|
||||
gdc_sw_reset ();
|
||||
puts ("gdc reset done after drawing engine lock.\n");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void de_wait_slots (int slots)
|
||||
{
|
||||
GraphicDevice *dev = &mb862xx;
|
||||
int lc = 0x10000;
|
||||
|
||||
/* Wait for free fifo slots */
|
||||
while (DE_RD_REG (GC_IFCNT) < slots)
|
||||
if (lc-- < 0) {
|
||||
gdc_sw_reset ();
|
||||
puts ("gdc reset done after drawing engine lock.\n");
|
||||
break;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#if !defined(CONFIG_VIDEO_CORALP)
|
||||
static void board_disp_init (void)
|
||||
{
|
||||
GraphicDevice *dev = &mb862xx;
|
||||
const gdc_regs *regs = board_get_regs ();
|
||||
|
||||
while (regs->index) {
|
||||
DISP_WR_REG (regs->index, regs->value);
|
||||
regs++;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Init drawing engine if accel enabled.
|
||||
* Also clears visible framebuffer.
|
||||
*/
|
||||
static void de_init (void)
|
||||
{
|
||||
GraphicDevice *dev = &mb862xx;
|
||||
#if defined(CONFIG_VIDEO_MB862xx_ACCEL)
|
||||
int cf = (dev->gdfBytesPP == 1) ? 0x0000 : 0x8000;
|
||||
|
||||
dev->dprBase = dev->frameAdrs + GC_DRAW_BASE;
|
||||
|
||||
/* Setup mode and fbbase, xres, fg, bg */
|
||||
de_wait_slots (2);
|
||||
DE_WR_FIFO (0xf1010108);
|
||||
DE_WR_FIFO (cf | 0x0300);
|
||||
DE_WR_REG (GC_FBR, 0x0);
|
||||
DE_WR_REG (GC_XRES, dev->winSizeX);
|
||||
DE_WR_REG (GC_FC, 0x0);
|
||||
DE_WR_REG (GC_BC, 0x0);
|
||||
/* Reset clipping */
|
||||
DE_WR_REG (GC_CXMIN, 0x0);
|
||||
DE_WR_REG (GC_CXMAX, dev->winSizeX);
|
||||
DE_WR_REG (GC_CYMIN, 0x0);
|
||||
DE_WR_REG (GC_CYMAX, dev->winSizeY);
|
||||
|
||||
/* Clear framebuffer using drawing engine */
|
||||
de_wait_slots (3);
|
||||
DE_WR_FIFO (0x09410000);
|
||||
DE_WR_FIFO (0x00000000);
|
||||
DE_WR_FIFO (dev->winSizeY << 16 | dev->winSizeX);
|
||||
/* sync with SW access to framebuffer */
|
||||
de_wait ();
|
||||
#else
|
||||
unsigned int i, *p;
|
||||
|
||||
i = dev->winSizeX * dev->winSizeY;
|
||||
p = (unsigned int *)dev->frameAdrs;
|
||||
while (i--)
|
||||
*p++ = 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
#if defined(CONFIG_VIDEO_CORALP)
|
||||
/* use CCF and MMR parameters for Coral-P Eval. Board as default */
|
||||
#ifndef CONFIG_SYS_MB862xx_CCF
|
||||
#define CONFIG_SYS_MB862xx_CCF 0x00090000
|
||||
#endif
|
||||
#ifndef CONFIG_SYS_MB862xx_MMR
|
||||
#define CONFIG_SYS_MB862xx_MMR 0x11d7fa13
|
||||
#endif
|
||||
|
||||
unsigned int pci_video_init (void)
|
||||
{
|
||||
GraphicDevice *dev = &mb862xx;
|
||||
pci_dev_t devbusfn;
|
||||
u16 device;
|
||||
|
||||
if ((devbusfn = pci_find_devices (supported, 0)) < 0) {
|
||||
puts("controller not present\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* PCI setup */
|
||||
pci_write_config_dword (devbusfn, PCI_COMMAND,
|
||||
(PCI_COMMAND_MEMORY | PCI_COMMAND_IO));
|
||||
pci_read_config_dword (devbusfn, PCI_BASE_ADDRESS_0, &dev->frameAdrs);
|
||||
dev->frameAdrs = pci_mem_to_phys (devbusfn, dev->frameAdrs);
|
||||
|
||||
if (dev->frameAdrs == 0) {
|
||||
puts ("PCI config: failed to get base address\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
dev->pciBase = dev->frameAdrs;
|
||||
|
||||
puts("Coral-");
|
||||
|
||||
pci_read_config_word(devbusfn, PCI_DEVICE_ID, &device);
|
||||
switch (device) {
|
||||
case PCI_DEVICE_ID_CORAL_P:
|
||||
puts("P\n");
|
||||
break;
|
||||
case PCI_DEVICE_ID_CORAL_PA:
|
||||
puts("PA\n");
|
||||
break;
|
||||
default:
|
||||
puts("Unknown\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Setup clocks and memory mode for Coral-P(A) */
|
||||
HOST_WR_REG(GC_CCF, CONFIG_SYS_MB862xx_CCF);
|
||||
udelay (200);
|
||||
HOST_WR_REG(GC_MMR, CONFIG_SYS_MB862xx_MMR);
|
||||
udelay (100);
|
||||
return dev->frameAdrs;
|
||||
}
|
||||
|
||||
unsigned int card_init (void)
|
||||
{
|
||||
GraphicDevice *dev = &mb862xx;
|
||||
unsigned int cf, videomode, div = 0;
|
||||
unsigned long t1, hsync, vsync;
|
||||
char *penv;
|
||||
int tmp, i, bpp;
|
||||
struct ctfb_res_modes *res_mode;
|
||||
struct ctfb_res_modes var_mode;
|
||||
|
||||
memset (dev, 0, sizeof (GraphicDevice));
|
||||
|
||||
if (!pci_video_init ())
|
||||
return 0;
|
||||
|
||||
tmp = 0;
|
||||
videomode = 0x310;
|
||||
/* get video mode via environment */
|
||||
if ((penv = getenv ("videomode")) != NULL) {
|
||||
/* decide if it is a string */
|
||||
if (penv[0] <= '9') {
|
||||
videomode = (int) simple_strtoul (penv, NULL, 16);
|
||||
tmp = 1;
|
||||
}
|
||||
} else {
|
||||
tmp = 1;
|
||||
}
|
||||
|
||||
if (tmp) {
|
||||
/* parameter are vesa modes, search params */
|
||||
for (i = 0; i < VESA_MODES_COUNT; i++) {
|
||||
if (vesa_modes[i].vesanr == videomode)
|
||||
break;
|
||||
}
|
||||
if (i == VESA_MODES_COUNT) {
|
||||
printf ("\tno VESA Mode found, fallback to mode 0x%x\n",
|
||||
videomode);
|
||||
i = 0;
|
||||
}
|
||||
res_mode = (struct ctfb_res_modes *)
|
||||
&res_mode_init[vesa_modes[i].resindex];
|
||||
if (vesa_modes[i].resindex > 2) {
|
||||
puts ("\tUnsupported resolution, using default\n");
|
||||
bpp = vesa_modes[1].bits_per_pixel;
|
||||
div = fr_div[1];
|
||||
}
|
||||
bpp = vesa_modes[i].bits_per_pixel;
|
||||
div = fr_div[vesa_modes[i].resindex];
|
||||
} else {
|
||||
res_mode = (struct ctfb_res_modes *) &var_mode;
|
||||
bpp = video_get_params (res_mode, penv);
|
||||
}
|
||||
|
||||
/* calculate hsync and vsync freq (info only) */
|
||||
t1 = (res_mode->left_margin + res_mode->xres +
|
||||
res_mode->right_margin + res_mode->hsync_len) / 8;
|
||||
t1 *= 8;
|
||||
t1 *= res_mode->pixclock;
|
||||
t1 /= 1000;
|
||||
hsync = 1000000000L / t1;
|
||||
t1 *= (res_mode->upper_margin + res_mode->yres +
|
||||
res_mode->lower_margin + res_mode->vsync_len);
|
||||
t1 /= 1000;
|
||||
vsync = 1000000000L / t1;
|
||||
|
||||
/* fill in Graphic device struct */
|
||||
sprintf (dev->modeIdent, "%dx%dx%d %ldkHz %ldHz", res_mode->xres,
|
||||
res_mode->yres, bpp, (hsync / 1000), (vsync / 1000));
|
||||
printf ("\t%s\n", dev->modeIdent);
|
||||
dev->winSizeX = res_mode->xres;
|
||||
dev->winSizeY = res_mode->yres;
|
||||
dev->memSize = VIDEO_MEM_SIZE;
|
||||
|
||||
switch (bpp) {
|
||||
case 8:
|
||||
dev->gdfIndex = GDF__8BIT_INDEX;
|
||||
dev->gdfBytesPP = 1;
|
||||
break;
|
||||
case 15:
|
||||
case 16:
|
||||
dev->gdfIndex = GDF_15BIT_555RGB;
|
||||
dev->gdfBytesPP = 2;
|
||||
break;
|
||||
default:
|
||||
printf ("\t%d bpp configured, but only 8,15 and 16 supported\n",
|
||||
bpp);
|
||||
puts ("\tfallback to 15bpp\n");
|
||||
dev->gdfIndex = GDF_15BIT_555RGB;
|
||||
dev->gdfBytesPP = 2;
|
||||
}
|
||||
|
||||
/* Setup dot clock (internal pll, division rate) */
|
||||
DISP_WR_REG (GC_DCM1, div);
|
||||
/* L0 init */
|
||||
cf = (dev->gdfBytesPP == 1) ? 0x00000000 : 0x80000000;
|
||||
DISP_WR_REG (GC_L0M, ((dev->winSizeX * dev->gdfBytesPP) / 64) << 16 |
|
||||
(dev->winSizeY - 1) | cf);
|
||||
DISP_WR_REG (GC_L0OA0, 0x0);
|
||||
DISP_WR_REG (GC_L0DA0, 0x0);
|
||||
DISP_WR_REG (GC_L0DY_L0DX, 0x0);
|
||||
DISP_WR_REG (GC_L0EM, 0x0);
|
||||
DISP_WR_REG (GC_L0WY_L0WX, 0x0);
|
||||
DISP_WR_REG (GC_L0WH_L0WW, (dev->winSizeY - 1) << 16 | dev->winSizeX);
|
||||
|
||||
/* Display timing init */
|
||||
DISP_WR_REG (GC_HTP_A, (dev->winSizeX +
|
||||
res_mode->left_margin +
|
||||
res_mode->right_margin +
|
||||
res_mode->hsync_len - 1) << 16);
|
||||
DISP_WR_REG (GC_HDB_HDP_A, (dev->winSizeX - 1) << 16 |
|
||||
(dev->winSizeX - 1));
|
||||
DISP_WR_REG (GC_VSW_HSW_HSP_A, (res_mode->vsync_len - 1) << 24 |
|
||||
(res_mode->hsync_len - 1) << 16 |
|
||||
(dev->winSizeX +
|
||||
res_mode->right_margin - 1));
|
||||
DISP_WR_REG (GC_VTR_A, (dev->winSizeY + res_mode->lower_margin +
|
||||
res_mode->upper_margin +
|
||||
res_mode->vsync_len - 1) << 16);
|
||||
DISP_WR_REG (GC_VDP_VSP_A, (dev->winSizeY-1) << 16 |
|
||||
(dev->winSizeY +
|
||||
res_mode->lower_margin - 1));
|
||||
DISP_WR_REG (GC_WY_WX, 0x0);
|
||||
DISP_WR_REG (GC_WH_WW, dev->winSizeY << 16 | dev->winSizeX);
|
||||
/* Display enable, L0 layer */
|
||||
DISP_WR_REG (GC_DCM1, 0x80010000 | div);
|
||||
|
||||
return dev->frameAdrs;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
#if !defined(CONFIG_VIDEO_CORALP)
|
||||
int mb862xx_probe(unsigned int addr)
|
||||
{
|
||||
GraphicDevice *dev = &mb862xx;
|
||||
unsigned int reg;
|
||||
|
||||
dev->frameAdrs = addr;
|
||||
dev->dprBase = dev->frameAdrs + GC_DRAW_BASE;
|
||||
|
||||
/* Try to access GDC ID/Revision registers */
|
||||
reg = HOST_RD_REG (GC_CID);
|
||||
reg = HOST_RD_REG (GC_CID);
|
||||
if (reg == 0x303) {
|
||||
reg = DE_RD_REG(GC_REV);
|
||||
reg = DE_RD_REG(GC_REV);
|
||||
if ((reg & ~0xff) == 0x20050100)
|
||||
return MB862XX_TYPE_LIME;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
void *video_hw_init (void)
|
||||
{
|
||||
GraphicDevice *dev = &mb862xx;
|
||||
|
||||
puts ("Video: Fujitsu ");
|
||||
|
||||
memset (dev, 0, sizeof (GraphicDevice));
|
||||
|
||||
#if defined(CONFIG_VIDEO_CORALP)
|
||||
if (card_init () == 0)
|
||||
return NULL;
|
||||
#else
|
||||
/*
|
||||
* Preliminary init of the onboard graphic controller,
|
||||
* retrieve base address
|
||||
*/
|
||||
if ((dev->frameAdrs = board_video_init ()) == 0) {
|
||||
puts ("Controller not found!\n");
|
||||
return NULL;
|
||||
} else {
|
||||
puts ("Lime\n");
|
||||
|
||||
/* Set Change of Clock Frequency Register */
|
||||
HOST_WR_REG (GC_CCF, CONFIG_SYS_MB862xx_CCF);
|
||||
/* Delay required */
|
||||
udelay(300);
|
||||
/* Set Memory I/F Mode Register) */
|
||||
HOST_WR_REG (GC_MMR, CONFIG_SYS_MB862xx_MMR);
|
||||
}
|
||||
#endif
|
||||
|
||||
de_init ();
|
||||
|
||||
#if !defined(CONFIG_VIDEO_CORALP)
|
||||
board_disp_init ();
|
||||
#endif
|
||||
|
||||
#if (defined(CONFIG_LWMON5) || \
|
||||
defined(CONFIG_SOCRATES)) && !(CONFIG_POST & CONFIG_SYS_POST_SYSMON)
|
||||
/* Lamp on */
|
||||
board_backlight_switch (1);
|
||||
#endif
|
||||
|
||||
return dev;
|
||||
}
|
||||
|
||||
/*
|
||||
* Set a RGB color in the LUT
|
||||
*/
|
||||
void video_set_lut (unsigned int index, unsigned char r,
|
||||
unsigned char g, unsigned char b)
|
||||
{
|
||||
GraphicDevice *dev = &mb862xx;
|
||||
|
||||
L0PAL_WR_REG (index, (r << 16) | (g << 8) | (b));
|
||||
}
|
||||
|
||||
#if defined(CONFIG_VIDEO_MB862xx_ACCEL)
|
||||
/*
|
||||
* Drawing engine Fill and BitBlt screen region
|
||||
*/
|
||||
void video_hw_rectfill (unsigned int bpp, unsigned int dst_x,
|
||||
unsigned int dst_y, unsigned int dim_x,
|
||||
unsigned int dim_y, unsigned int color)
|
||||
{
|
||||
GraphicDevice *dev = &mb862xx;
|
||||
|
||||
de_wait_slots (3);
|
||||
DE_WR_REG (GC_FC, color);
|
||||
DE_WR_FIFO (0x09410000);
|
||||
DE_WR_FIFO ((dst_y << 16) | dst_x);
|
||||
DE_WR_FIFO ((dim_y << 16) | dim_x);
|
||||
de_wait ();
|
||||
}
|
||||
|
||||
void video_hw_bitblt (unsigned int bpp, unsigned int src_x,
|
||||
unsigned int src_y, unsigned int dst_x,
|
||||
unsigned int dst_y, unsigned int width,
|
||||
unsigned int height)
|
||||
{
|
||||
GraphicDevice *dev = &mb862xx;
|
||||
unsigned int ctrl = 0x0d000000L;
|
||||
|
||||
if (src_x >= dst_x && src_y >= dst_y)
|
||||
ctrl |= 0x00440000L;
|
||||
else if (src_x >= dst_x && src_y <= dst_y)
|
||||
ctrl |= 0x00460000L;
|
||||
else if (src_x <= dst_x && src_y >= dst_y)
|
||||
ctrl |= 0x00450000L;
|
||||
else
|
||||
ctrl |= 0x00470000L;
|
||||
|
||||
de_wait_slots (4);
|
||||
DE_WR_FIFO (ctrl);
|
||||
DE_WR_FIFO ((src_y << 16) | src_x);
|
||||
DE_WR_FIFO ((dst_y << 16) | dst_x);
|
||||
DE_WR_FIFO ((height << 16) | width);
|
||||
de_wait (); /* sync */
|
||||
}
|
||||
#endif
|
||||
184
common/package/boot/uboot-ipq40xx/src/drivers/video/mb86r0xgdc.c
Normal file
184
common/package/boot/uboot-ipq40xx/src/drivers/video/mb86r0xgdc.c
Normal file
|
|
@ -0,0 +1,184 @@
|
|||
/*
|
||||
* (C) Copyright 2010
|
||||
* Matthias Weisser <weisserm@arcor.de>
|
||||
*
|
||||
* See file CREDITS for list of people who contributed to this
|
||||
* project.
|
||||
*
|
||||
* 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
|
||||
*/
|
||||
|
||||
/*
|
||||
* mb86r0xgdc.c - Graphic interface for Fujitsu MB86R0x integrated graphic
|
||||
* controller.
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
|
||||
#include <malloc.h>
|
||||
#include <asm/io.h>
|
||||
#include <asm/arch/hardware.h>
|
||||
#include <video_fb.h>
|
||||
#include "videomodes.h"
|
||||
|
||||
/*
|
||||
* 4MB (at the end of system RAM)
|
||||
*/
|
||||
#define VIDEO_MEM_SIZE 0x400000
|
||||
|
||||
#define FB_SYNC_CLK_INV (1<<16) /* pixel clock inverted */
|
||||
|
||||
/*
|
||||
* Graphic Device
|
||||
*/
|
||||
static GraphicDevice mb86r0x;
|
||||
|
||||
static void dsp_init(struct mb86r0x_gdc_dsp *dsp, char *modestr,
|
||||
u32 *videomem)
|
||||
{
|
||||
struct ctfb_res_modes var_mode;
|
||||
u32 dcm1, dcm2, dcm3;
|
||||
u16 htp, hdp, hdb, hsp, vtr, vsp, vdp;
|
||||
u8 hsw, vsw;
|
||||
u32 l2m, l2em, l2oa0, l2da0, l2oa1, l2da1;
|
||||
u16 l2dx, l2dy, l2wx, l2wy, l2ww, l2wh;
|
||||
unsigned long div;
|
||||
int bpp;
|
||||
|
||||
bpp = video_get_params(&var_mode, modestr);
|
||||
|
||||
if (bpp == 0) {
|
||||
var_mode.xres = 640;
|
||||
var_mode.yres = 480;
|
||||
var_mode.pixclock = 39721; /* 25MHz */
|
||||
var_mode.left_margin = 48;
|
||||
var_mode.right_margin = 16;
|
||||
var_mode.upper_margin = 33;
|
||||
var_mode.lower_margin = 10;
|
||||
var_mode.hsync_len = 96;
|
||||
var_mode.vsync_len = 2;
|
||||
var_mode.sync = 0;
|
||||
var_mode.vmode = 0;
|
||||
bpp = 15;
|
||||
}
|
||||
|
||||
/* Fill memory with white */
|
||||
memset(videomem, 0xFF, var_mode.xres * var_mode.yres * 2);
|
||||
|
||||
mb86r0x.winSizeX = var_mode.xres;
|
||||
mb86r0x.winSizeY = var_mode.yres;
|
||||
|
||||
/* LCD base clock is ~ 660MHZ. We do calculations in kHz */
|
||||
div = 660000 / (1000000000L / var_mode.pixclock);
|
||||
if (div > 64)
|
||||
div = 64;
|
||||
if (0 == div)
|
||||
div = 1;
|
||||
|
||||
dcm1 = (div - 1) << 8;
|
||||
dcm2 = 0x00000000;
|
||||
if (var_mode.sync & FB_SYNC_CLK_INV)
|
||||
dcm3 = 0x00000100;
|
||||
else
|
||||
dcm3 = 0x00000000;
|
||||
|
||||
htp = var_mode.left_margin + var_mode.xres +
|
||||
var_mode.hsync_len + var_mode.right_margin;
|
||||
hdp = var_mode.xres;
|
||||
hdb = var_mode.xres;
|
||||
hsp = var_mode.xres + var_mode.right_margin;
|
||||
hsw = var_mode.hsync_len;
|
||||
|
||||
vsw = var_mode.vsync_len;
|
||||
vtr = var_mode.upper_margin + var_mode.yres +
|
||||
var_mode.vsync_len + var_mode.lower_margin;
|
||||
vsp = var_mode.yres + var_mode.lower_margin;
|
||||
vdp = var_mode.yres;
|
||||
|
||||
l2m = ((var_mode.yres - 1) << (0)) |
|
||||
(((var_mode.xres * 2) / 64) << (16)) |
|
||||
((1) << (31));
|
||||
|
||||
l2em = (1 << 0) | (1 << 1);
|
||||
|
||||
l2oa0 = mb86r0x.frameAdrs;
|
||||
l2da0 = mb86r0x.frameAdrs;
|
||||
l2oa1 = mb86r0x.frameAdrs;
|
||||
l2da1 = mb86r0x.frameAdrs;
|
||||
l2dx = 0;
|
||||
l2dy = 0;
|
||||
l2wx = 0;
|
||||
l2wy = 0;
|
||||
l2ww = var_mode.xres;
|
||||
l2wh = var_mode.yres - 1;
|
||||
|
||||
writel(dcm1, &dsp->dcm1);
|
||||
writel(dcm2, &dsp->dcm2);
|
||||
writel(dcm3, &dsp->dcm3);
|
||||
|
||||
writew(htp, &dsp->htp);
|
||||
writew(hdp, &dsp->hdp);
|
||||
writew(hdb, &dsp->hdb);
|
||||
writew(hsp, &dsp->hsp);
|
||||
writeb(hsw, &dsp->hsw);
|
||||
|
||||
writeb(vsw, &dsp->vsw);
|
||||
writew(vtr, &dsp->vtr);
|
||||
writew(vsp, &dsp->vsp);
|
||||
writew(vdp, &dsp->vdp);
|
||||
|
||||
writel(l2m, &dsp->l2m);
|
||||
writel(l2em, &dsp->l2em);
|
||||
writel(l2oa0, &dsp->l2oa0);
|
||||
writel(l2da0, &dsp->l2da0);
|
||||
writel(l2oa1, &dsp->l2oa1);
|
||||
writel(l2da1, &dsp->l2da1);
|
||||
writew(l2dx, &dsp->l2dx);
|
||||
writew(l2dy, &dsp->l2dy);
|
||||
writew(l2wx, &dsp->l2wx);
|
||||
writew(l2wy, &dsp->l2wy);
|
||||
writew(l2ww, &dsp->l2ww);
|
||||
writew(l2wh, &dsp->l2wh);
|
||||
|
||||
writel(dcm1 | (1 << 18) | (1 << 31), &dsp->dcm1);
|
||||
}
|
||||
|
||||
void *video_hw_init(void)
|
||||
{
|
||||
struct mb86r0x_gdc *gdc = (struct mb86r0x_gdc *) MB86R0x_GDC_BASE;
|
||||
GraphicDevice *pGD = &mb86r0x;
|
||||
char *s;
|
||||
u32 *vid;
|
||||
|
||||
memset(pGD, 0, sizeof(GraphicDevice));
|
||||
|
||||
pGD->gdfIndex = GDF_15BIT_555RGB;
|
||||
pGD->gdfBytesPP = 2;
|
||||
pGD->memSize = VIDEO_MEM_SIZE;
|
||||
pGD->frameAdrs = PHYS_SDRAM + PHYS_SDRAM_SIZE - VIDEO_MEM_SIZE;
|
||||
|
||||
vid = (u32 *)pGD->frameAdrs;
|
||||
|
||||
s = getenv("videomode");
|
||||
if (s != NULL)
|
||||
dsp_init(&gdc->dsp0, s, vid);
|
||||
|
||||
s = getenv("videomode1");
|
||||
if (s != NULL)
|
||||
dsp_init(&gdc->dsp1, s, vid);
|
||||
|
||||
return pGD;
|
||||
}
|
||||
931
common/package/boot/uboot-ipq40xx/src/drivers/video/mx3fb.c
Normal file
931
common/package/boot/uboot-ipq40xx/src/drivers/video/mx3fb.c
Normal file
|
|
@ -0,0 +1,931 @@
|
|||
/*
|
||||
* Copyright (C) 2009
|
||||
* Guennadi Liakhovetski, DENX Software Engineering, <lg@denx.de>
|
||||
* Copyright (C) 2011
|
||||
* HALE electronic GmbH, <helmut.raiger@hale.at>
|
||||
*
|
||||
* See file CREDITS for list of people who contributed to this
|
||||
* project.
|
||||
*
|
||||
* 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 <common.h>
|
||||
#include <malloc.h>
|
||||
#include <video_fb.h>
|
||||
|
||||
#include <asm/arch/imx-regs.h>
|
||||
#include <asm/arch/clock.h>
|
||||
#include <asm/errno.h>
|
||||
#include <asm/io.h>
|
||||
|
||||
#include "videomodes.h"
|
||||
|
||||
/* this might need panel specific set-up as-well */
|
||||
#define IF_CONF 0
|
||||
|
||||
/* -------------- controller specific stuff -------------- */
|
||||
|
||||
/* IPU DMA Controller channel definitions. */
|
||||
enum ipu_channel {
|
||||
IDMAC_IC_0 = 0, /* IC (encoding task) to memory */
|
||||
IDMAC_IC_1 = 1, /* IC (viewfinder task) to memory */
|
||||
IDMAC_ADC_0 = 1,
|
||||
IDMAC_IC_2 = 2,
|
||||
IDMAC_ADC_1 = 2,
|
||||
IDMAC_IC_3 = 3,
|
||||
IDMAC_IC_4 = 4,
|
||||
IDMAC_IC_5 = 5,
|
||||
IDMAC_IC_6 = 6,
|
||||
IDMAC_IC_7 = 7, /* IC (sensor data) to memory */
|
||||
IDMAC_IC_8 = 8,
|
||||
IDMAC_IC_9 = 9,
|
||||
IDMAC_IC_10 = 10,
|
||||
IDMAC_IC_11 = 11,
|
||||
IDMAC_IC_12 = 12,
|
||||
IDMAC_IC_13 = 13,
|
||||
IDMAC_SDC_0 = 14, /* Background synchronous display data */
|
||||
IDMAC_SDC_1 = 15, /* Foreground data (overlay) */
|
||||
IDMAC_SDC_2 = 16,
|
||||
IDMAC_SDC_3 = 17,
|
||||
IDMAC_ADC_2 = 18,
|
||||
IDMAC_ADC_3 = 19,
|
||||
IDMAC_ADC_4 = 20,
|
||||
IDMAC_ADC_5 = 21,
|
||||
IDMAC_ADC_6 = 22,
|
||||
IDMAC_ADC_7 = 23,
|
||||
IDMAC_PF_0 = 24,
|
||||
IDMAC_PF_1 = 25,
|
||||
IDMAC_PF_2 = 26,
|
||||
IDMAC_PF_3 = 27,
|
||||
IDMAC_PF_4 = 28,
|
||||
IDMAC_PF_5 = 29,
|
||||
IDMAC_PF_6 = 30,
|
||||
IDMAC_PF_7 = 31,
|
||||
};
|
||||
|
||||
/* More formats can be copied from the Linux driver if needed */
|
||||
enum pixel_fmt {
|
||||
/* 2 bytes */
|
||||
IPU_PIX_FMT_RGB565,
|
||||
IPU_PIX_FMT_RGB666,
|
||||
IPU_PIX_FMT_BGR666,
|
||||
/* 3 bytes */
|
||||
IPU_PIX_FMT_RGB24,
|
||||
};
|
||||
|
||||
struct pixel_fmt_cfg {
|
||||
u32 b0;
|
||||
u32 b1;
|
||||
u32 b2;
|
||||
u32 acc;
|
||||
};
|
||||
|
||||
static struct pixel_fmt_cfg fmt_cfg[] = {
|
||||
[IPU_PIX_FMT_RGB24] = {
|
||||
0x1600AAAA, 0x00E05555, 0x00070000, 3,
|
||||
},
|
||||
[IPU_PIX_FMT_RGB666] = {
|
||||
0x0005000F, 0x000B000F, 0x0011000F, 1,
|
||||
},
|
||||
[IPU_PIX_FMT_BGR666] = {
|
||||
0x0011000F, 0x000B000F, 0x0005000F, 1,
|
||||
},
|
||||
[IPU_PIX_FMT_RGB565] = {
|
||||
0x0004003F, 0x000A000F, 0x000F003F, 1,
|
||||
}
|
||||
};
|
||||
|
||||
enum ipu_panel {
|
||||
IPU_PANEL_SHARP_TFT,
|
||||
IPU_PANEL_TFT,
|
||||
};
|
||||
|
||||
/* IPU Common registers */
|
||||
/* IPU_CONF and its bits already defined in imx-regs.h */
|
||||
#define IPU_CHA_BUF0_RDY (0x04 + IPU_BASE)
|
||||
#define IPU_CHA_BUF1_RDY (0x08 + IPU_BASE)
|
||||
#define IPU_CHA_DB_MODE_SEL (0x0C + IPU_BASE)
|
||||
#define IPU_CHA_CUR_BUF (0x10 + IPU_BASE)
|
||||
#define IPU_FS_PROC_FLOW (0x14 + IPU_BASE)
|
||||
#define IPU_FS_DISP_FLOW (0x18 + IPU_BASE)
|
||||
#define IPU_TASKS_STAT (0x1C + IPU_BASE)
|
||||
#define IPU_IMA_ADDR (0x20 + IPU_BASE)
|
||||
#define IPU_IMA_DATA (0x24 + IPU_BASE)
|
||||
#define IPU_INT_CTRL_1 (0x28 + IPU_BASE)
|
||||
#define IPU_INT_CTRL_2 (0x2C + IPU_BASE)
|
||||
#define IPU_INT_CTRL_3 (0x30 + IPU_BASE)
|
||||
#define IPU_INT_CTRL_4 (0x34 + IPU_BASE)
|
||||
#define IPU_INT_CTRL_5 (0x38 + IPU_BASE)
|
||||
#define IPU_INT_STAT_1 (0x3C + IPU_BASE)
|
||||
#define IPU_INT_STAT_2 (0x40 + IPU_BASE)
|
||||
#define IPU_INT_STAT_3 (0x44 + IPU_BASE)
|
||||
#define IPU_INT_STAT_4 (0x48 + IPU_BASE)
|
||||
#define IPU_INT_STAT_5 (0x4C + IPU_BASE)
|
||||
#define IPU_BRK_CTRL_1 (0x50 + IPU_BASE)
|
||||
#define IPU_BRK_CTRL_2 (0x54 + IPU_BASE)
|
||||
#define IPU_BRK_STAT (0x58 + IPU_BASE)
|
||||
#define IPU_DIAGB_CTRL (0x5C + IPU_BASE)
|
||||
|
||||
/* Image Converter Registers */
|
||||
#define IC_CONF (0x88 + IPU_BASE)
|
||||
#define IC_PRP_ENC_RSC (0x8C + IPU_BASE)
|
||||
#define IC_PRP_VF_RSC (0x90 + IPU_BASE)
|
||||
#define IC_PP_RSC (0x94 + IPU_BASE)
|
||||
#define IC_CMBP_1 (0x98 + IPU_BASE)
|
||||
#define IC_CMBP_2 (0x9C + IPU_BASE)
|
||||
#define PF_CONF (0xA0 + IPU_BASE)
|
||||
#define IDMAC_CONF (0xA4 + IPU_BASE)
|
||||
#define IDMAC_CHA_EN (0xA8 + IPU_BASE)
|
||||
#define IDMAC_CHA_PRI (0xAC + IPU_BASE)
|
||||
#define IDMAC_CHA_BUSY (0xB0 + IPU_BASE)
|
||||
|
||||
/* Image Converter Register bits */
|
||||
#define IC_CONF_PRPENC_EN 0x00000001
|
||||
#define IC_CONF_PRPENC_CSC1 0x00000002
|
||||
#define IC_CONF_PRPENC_ROT_EN 0x00000004
|
||||
#define IC_CONF_PRPVF_EN 0x00000100
|
||||
#define IC_CONF_PRPVF_CSC1 0x00000200
|
||||
#define IC_CONF_PRPVF_CSC2 0x00000400
|
||||
#define IC_CONF_PRPVF_CMB 0x00000800
|
||||
#define IC_CONF_PRPVF_ROT_EN 0x00001000
|
||||
#define IC_CONF_PP_EN 0x00010000
|
||||
#define IC_CONF_PP_CSC1 0x00020000
|
||||
#define IC_CONF_PP_CSC2 0x00040000
|
||||
#define IC_CONF_PP_CMB 0x00080000
|
||||
#define IC_CONF_PP_ROT_EN 0x00100000
|
||||
#define IC_CONF_IC_GLB_LOC_A 0x10000000
|
||||
#define IC_CONF_KEY_COLOR_EN 0x20000000
|
||||
#define IC_CONF_RWS_EN 0x40000000
|
||||
#define IC_CONF_CSI_MEM_WR_EN 0x80000000
|
||||
|
||||
/* SDC Registers */
|
||||
#define SDC_COM_CONF (0xB4 + IPU_BASE)
|
||||
#define SDC_GW_CTRL (0xB8 + IPU_BASE)
|
||||
#define SDC_FG_POS (0xBC + IPU_BASE)
|
||||
#define SDC_BG_POS (0xC0 + IPU_BASE)
|
||||
#define SDC_CUR_POS (0xC4 + IPU_BASE)
|
||||
#define SDC_PWM_CTRL (0xC8 + IPU_BASE)
|
||||
#define SDC_CUR_MAP (0xCC + IPU_BASE)
|
||||
#define SDC_HOR_CONF (0xD0 + IPU_BASE)
|
||||
#define SDC_VER_CONF (0xD4 + IPU_BASE)
|
||||
#define SDC_SHARP_CONF_1 (0xD8 + IPU_BASE)
|
||||
#define SDC_SHARP_CONF_2 (0xDC + IPU_BASE)
|
||||
|
||||
/* Register bits */
|
||||
#define SDC_COM_TFT_COLOR 0x00000001UL
|
||||
#define SDC_COM_FG_EN 0x00000010UL
|
||||
#define SDC_COM_GWSEL 0x00000020UL
|
||||
#define SDC_COM_GLB_A 0x00000040UL
|
||||
#define SDC_COM_KEY_COLOR_G 0x00000080UL
|
||||
#define SDC_COM_BG_EN 0x00000200UL
|
||||
#define SDC_COM_SHARP 0x00001000UL
|
||||
|
||||
#define SDC_V_SYNC_WIDTH_L 0x00000001UL
|
||||
|
||||
/* Display Interface registers */
|
||||
#define DI_DISP_IF_CONF (0x0124 + IPU_BASE)
|
||||
#define DI_DISP_SIG_POL (0x0128 + IPU_BASE)
|
||||
#define DI_SER_DISP1_CONF (0x012C + IPU_BASE)
|
||||
#define DI_SER_DISP2_CONF (0x0130 + IPU_BASE)
|
||||
#define DI_HSP_CLK_PER (0x0134 + IPU_BASE)
|
||||
#define DI_DISP0_TIME_CONF_1 (0x0138 + IPU_BASE)
|
||||
#define DI_DISP0_TIME_CONF_2 (0x013C + IPU_BASE)
|
||||
#define DI_DISP0_TIME_CONF_3 (0x0140 + IPU_BASE)
|
||||
#define DI_DISP1_TIME_CONF_1 (0x0144 + IPU_BASE)
|
||||
#define DI_DISP1_TIME_CONF_2 (0x0148 + IPU_BASE)
|
||||
#define DI_DISP1_TIME_CONF_3 (0x014C + IPU_BASE)
|
||||
#define DI_DISP2_TIME_CONF_1 (0x0150 + IPU_BASE)
|
||||
#define DI_DISP2_TIME_CONF_2 (0x0154 + IPU_BASE)
|
||||
#define DI_DISP2_TIME_CONF_3 (0x0158 + IPU_BASE)
|
||||
#define DI_DISP3_TIME_CONF (0x015C + IPU_BASE)
|
||||
#define DI_DISP0_DB0_MAP (0x0160 + IPU_BASE)
|
||||
#define DI_DISP0_DB1_MAP (0x0164 + IPU_BASE)
|
||||
#define DI_DISP0_DB2_MAP (0x0168 + IPU_BASE)
|
||||
#define DI_DISP0_CB0_MAP (0x016C + IPU_BASE)
|
||||
#define DI_DISP0_CB1_MAP (0x0170 + IPU_BASE)
|
||||
#define DI_DISP0_CB2_MAP (0x0174 + IPU_BASE)
|
||||
#define DI_DISP1_DB0_MAP (0x0178 + IPU_BASE)
|
||||
#define DI_DISP1_DB1_MAP (0x017C + IPU_BASE)
|
||||
#define DI_DISP1_DB2_MAP (0x0180 + IPU_BASE)
|
||||
#define DI_DISP1_CB0_MAP (0x0184 + IPU_BASE)
|
||||
#define DI_DISP1_CB1_MAP (0x0188 + IPU_BASE)
|
||||
#define DI_DISP1_CB2_MAP (0x018C + IPU_BASE)
|
||||
#define DI_DISP2_DB0_MAP (0x0190 + IPU_BASE)
|
||||
#define DI_DISP2_DB1_MAP (0x0194 + IPU_BASE)
|
||||
#define DI_DISP2_DB2_MAP (0x0198 + IPU_BASE)
|
||||
#define DI_DISP2_CB0_MAP (0x019C + IPU_BASE)
|
||||
#define DI_DISP2_CB1_MAP (0x01A0 + IPU_BASE)
|
||||
#define DI_DISP2_CB2_MAP (0x01A4 + IPU_BASE)
|
||||
#define DI_DISP3_B0_MAP (0x01A8 + IPU_BASE)
|
||||
#define DI_DISP3_B1_MAP (0x01AC + IPU_BASE)
|
||||
#define DI_DISP3_B2_MAP (0x01B0 + IPU_BASE)
|
||||
#define DI_DISP_ACC_CC (0x01B4 + IPU_BASE)
|
||||
#define DI_DISP_LLA_CONF (0x01B8 + IPU_BASE)
|
||||
#define DI_DISP_LLA_DATA (0x01BC + IPU_BASE)
|
||||
|
||||
/* DI_DISP_SIG_POL bits */
|
||||
#define DI_D3_VSYNC_POL (1 << 28)
|
||||
#define DI_D3_HSYNC_POL (1 << 27)
|
||||
#define DI_D3_DRDY_SHARP_POL (1 << 26)
|
||||
#define DI_D3_CLK_POL (1 << 25)
|
||||
#define DI_D3_DATA_POL (1 << 24)
|
||||
|
||||
/* DI_DISP_IF_CONF bits */
|
||||
#define DI_D3_CLK_IDLE (1 << 26)
|
||||
#define DI_D3_CLK_SEL (1 << 25)
|
||||
#define DI_D3_DATAMSK (1 << 24)
|
||||
|
||||
#define IOMUX_PADNUM_MASK 0x1ff
|
||||
#define IOMUX_GPIONUM_SHIFT 9
|
||||
#define IOMUX_GPIONUM_MASK (0xff << IOMUX_GPIONUM_SHIFT)
|
||||
|
||||
#define IOMUX_PIN(gpionum, padnum) ((padnum) & IOMUX_PADNUM_MASK)
|
||||
|
||||
#define IOMUX_MODE_L(pin, mode) IOMUX_MODE(((pin) + 0xc) ^ 3, mode)
|
||||
|
||||
struct chan_param_mem_planar {
|
||||
/* Word 0 */
|
||||
u32 xv:10;
|
||||
u32 yv:10;
|
||||
u32 xb:12;
|
||||
|
||||
u32 yb:12;
|
||||
u32 res1:2;
|
||||
u32 nsb:1;
|
||||
u32 lnpb:6;
|
||||
u32 ubo_l:11;
|
||||
|
||||
u32 ubo_h:15;
|
||||
u32 vbo_l:17;
|
||||
|
||||
u32 vbo_h:9;
|
||||
u32 res2:3;
|
||||
u32 fw:12;
|
||||
u32 fh_l:8;
|
||||
|
||||
u32 fh_h:4;
|
||||
u32 res3:28;
|
||||
|
||||
/* Word 1 */
|
||||
u32 eba0;
|
||||
|
||||
u32 eba1;
|
||||
|
||||
u32 bpp:3;
|
||||
u32 sl:14;
|
||||
u32 pfs:3;
|
||||
u32 bam:3;
|
||||
u32 res4:2;
|
||||
u32 npb:6;
|
||||
u32 res5:1;
|
||||
|
||||
u32 sat:2;
|
||||
u32 res6:30;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
struct chan_param_mem_interleaved {
|
||||
/* Word 0 */
|
||||
u32 xv:10;
|
||||
u32 yv:10;
|
||||
u32 xb:12;
|
||||
|
||||
u32 yb:12;
|
||||
u32 sce:1;
|
||||
u32 res1:1;
|
||||
u32 nsb:1;
|
||||
u32 lnpb:6;
|
||||
u32 sx:10;
|
||||
u32 sy_l:1;
|
||||
|
||||
u32 sy_h:9;
|
||||
u32 ns:10;
|
||||
u32 sm:10;
|
||||
u32 sdx_l:3;
|
||||
|
||||
u32 sdx_h:2;
|
||||
u32 sdy:5;
|
||||
u32 sdrx:1;
|
||||
u32 sdry:1;
|
||||
u32 sdr1:1;
|
||||
u32 res2:2;
|
||||
u32 fw:12;
|
||||
u32 fh_l:8;
|
||||
|
||||
u32 fh_h:4;
|
||||
u32 res3:28;
|
||||
|
||||
/* Word 1 */
|
||||
u32 eba0;
|
||||
|
||||
u32 eba1;
|
||||
|
||||
u32 bpp:3;
|
||||
u32 sl:14;
|
||||
u32 pfs:3;
|
||||
u32 bam:3;
|
||||
u32 res4:2;
|
||||
u32 npb:6;
|
||||
u32 res5:1;
|
||||
|
||||
u32 sat:2;
|
||||
u32 scc:1;
|
||||
u32 ofs0:5;
|
||||
u32 ofs1:5;
|
||||
u32 ofs2:5;
|
||||
u32 ofs3:5;
|
||||
u32 wid0:3;
|
||||
u32 wid1:3;
|
||||
u32 wid2:3;
|
||||
|
||||
u32 wid3:3;
|
||||
u32 dec_sel:1;
|
||||
u32 res6:28;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
union chan_param_mem {
|
||||
struct chan_param_mem_planar pp;
|
||||
struct chan_param_mem_interleaved ip;
|
||||
};
|
||||
|
||||
DECLARE_GLOBAL_DATA_PTR;
|
||||
|
||||
/* graphics setup */
|
||||
static GraphicDevice panel;
|
||||
static struct ctfb_res_modes *mode;
|
||||
static struct ctfb_res_modes var_mode;
|
||||
|
||||
/*
|
||||
* sdc_init_panel() - initialize a synchronous LCD panel.
|
||||
* @width: width of panel in pixels.
|
||||
* @height: height of panel in pixels.
|
||||
* @di_setup: pixel format of the frame buffer
|
||||
* @di_panel: either SHARP or normal TFT
|
||||
* @return: 0 on success or negative error code on failure.
|
||||
*/
|
||||
static int sdc_init_panel(u16 width, u16 height,
|
||||
enum pixel_fmt di_setup, enum ipu_panel di_panel)
|
||||
{
|
||||
u32 reg, div;
|
||||
uint32_t old_conf;
|
||||
int clock;
|
||||
|
||||
debug("%s(width=%d, height=%d)\n", __func__, width, height);
|
||||
|
||||
/* Init clocking, the IPU receives its clock from the hsp divder */
|
||||
clock = mxc_get_clock(MXC_IPU_CLK);
|
||||
if (clock < 0)
|
||||
return -EACCES;
|
||||
|
||||
/* Init panel size and blanking periods */
|
||||
reg = width + mode->left_margin + mode->right_margin - 1;
|
||||
if (reg > 1023) {
|
||||
printf("mx3fb: Display width too large, coerced to 1023!");
|
||||
reg = 1023;
|
||||
}
|
||||
reg = ((mode->hsync_len - 1) << 26) | (reg << 16);
|
||||
writel(reg, SDC_HOR_CONF);
|
||||
|
||||
reg = height + mode->upper_margin + mode->lower_margin - 1;
|
||||
if (reg > 1023) {
|
||||
printf("mx3fb: Display height too large, coerced to 1023!");
|
||||
reg = 1023;
|
||||
}
|
||||
reg = ((mode->vsync_len - 1) << 26) | SDC_V_SYNC_WIDTH_L | (reg << 16);
|
||||
writel(reg, SDC_VER_CONF);
|
||||
|
||||
switch (di_panel) {
|
||||
case IPU_PANEL_SHARP_TFT:
|
||||
writel(0x00FD0102L, SDC_SHARP_CONF_1);
|
||||
writel(0x00F500F4L, SDC_SHARP_CONF_2);
|
||||
writel(SDC_COM_SHARP | SDC_COM_TFT_COLOR, SDC_COM_CONF);
|
||||
/* TODO: probably IF_CONF must be adapted (see below)! */
|
||||
break;
|
||||
case IPU_PANEL_TFT:
|
||||
writel(SDC_COM_TFT_COLOR, SDC_COM_CONF);
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Calculate divider: The fractional part is 4 bits so simply
|
||||
* multiple by 2^4 to get it.
|
||||
*
|
||||
* Opposed to the kernel driver mode->pixclock is the time of one
|
||||
* pixel in pico seconds, so:
|
||||
* pixel_clk = 1e12 / mode->pixclock
|
||||
* div = ipu_clk * 16 / pixel_clk
|
||||
* leads to:
|
||||
* div = ipu_clk * 16 / (1e12 / mode->pixclock)
|
||||
* or:
|
||||
* div = ipu_clk * 16 * mode->pixclock / 1e12
|
||||
*
|
||||
* To avoid integer overflows this is split into 2 shifts and
|
||||
* one divide with sufficient accuracy:
|
||||
* 16*1024*128*476837 = 0.9999996682e12
|
||||
*/
|
||||
div = ((clock/1024) * (mode->pixclock/128)) / 476837;
|
||||
debug("hsp_clk is %d, div=%d\n", clock, div);
|
||||
/* coerce to not less than 4.0, not more than 255.9375 */
|
||||
if (div < 0x40)
|
||||
div = 0x40;
|
||||
else if (div > 0xFFF)
|
||||
div = 0xFFF;
|
||||
/* DISP3_IF_CLK_DOWN_WR is half the divider value and 2 less
|
||||
* fraction bits. Subtract 1 extra from DISP3_IF_CLK_DOWN_WR
|
||||
* based on timing debug DISP3_IF_CLK_UP_WR is 0
|
||||
*/
|
||||
writel((((div / 8) - 1) << 22) | div, DI_DISP3_TIME_CONF);
|
||||
|
||||
/* DI settings for display 3: clock idle (bit 26) during vsync */
|
||||
old_conf = readl(DI_DISP_IF_CONF) & 0x78FFFFFF;
|
||||
writel(old_conf | IF_CONF, DI_DISP_IF_CONF);
|
||||
|
||||
/* only set display 3 polarity bits */
|
||||
old_conf = readl(DI_DISP_SIG_POL) & 0xE0FFFFFF;
|
||||
writel(old_conf | mode->sync, DI_DISP_SIG_POL);
|
||||
|
||||
writel(fmt_cfg[di_setup].b0, DI_DISP3_B0_MAP);
|
||||
writel(fmt_cfg[di_setup].b1, DI_DISP3_B1_MAP);
|
||||
writel(fmt_cfg[di_setup].b2, DI_DISP3_B2_MAP);
|
||||
writel(readl(DI_DISP_ACC_CC) |
|
||||
((fmt_cfg[di_setup].acc - 1) << 12), DI_DISP_ACC_CC);
|
||||
|
||||
debug("DI_DISP_IF_CONF = 0x%08X\n", readl(DI_DISP_IF_CONF));
|
||||
debug("DI_DISP_SIG_POL = 0x%08X\n", readl(DI_DISP_SIG_POL));
|
||||
debug("DI_DISP3_TIME_CONF = 0x%08X\n", readl(DI_DISP3_TIME_CONF));
|
||||
debug("SDC_HOR_CONF = 0x%08X\n", readl(SDC_HOR_CONF));
|
||||
debug("SDC_VER_CONF = 0x%08X\n", readl(SDC_VER_CONF));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void ipu_ch_param_set_size(union chan_param_mem *params,
|
||||
uint pixelfmt, uint16_t width,
|
||||
uint16_t height, uint16_t stride)
|
||||
{
|
||||
debug("%s(pixelfmt=%d, width=%d, height=%d, stride=%d)\n",
|
||||
__func__, pixelfmt, width, height, stride);
|
||||
|
||||
params->pp.fw = width - 1;
|
||||
params->pp.fh_l = height - 1;
|
||||
params->pp.fh_h = (height - 1) >> 8;
|
||||
params->pp.sl = stride - 1;
|
||||
|
||||
/* See above, for further formats see the Linux driver */
|
||||
switch (pixelfmt) {
|
||||
case GDF_16BIT_565RGB:
|
||||
params->ip.bpp = 2;
|
||||
params->ip.pfs = 4;
|
||||
params->ip.npb = 7;
|
||||
params->ip.sat = 2; /* SAT = 32-bit access */
|
||||
params->ip.ofs0 = 0; /* Red bit offset */
|
||||
params->ip.ofs1 = 5; /* Green bit offset */
|
||||
params->ip.ofs2 = 11; /* Blue bit offset */
|
||||
params->ip.ofs3 = 16; /* Alpha bit offset */
|
||||
params->ip.wid0 = 4; /* Red bit width - 1 */
|
||||
params->ip.wid1 = 5; /* Green bit width - 1 */
|
||||
params->ip.wid2 = 4; /* Blue bit width - 1 */
|
||||
break;
|
||||
case GDF_32BIT_X888RGB:
|
||||
params->ip.bpp = 1; /* 24 BPP & RGB PFS */
|
||||
params->ip.pfs = 4;
|
||||
params->ip.npb = 7;
|
||||
params->ip.sat = 2; /* SAT = 32-bit access */
|
||||
params->ip.ofs0 = 16; /* Red bit offset */
|
||||
params->ip.ofs1 = 8; /* Green bit offset */
|
||||
params->ip.ofs2 = 0; /* Blue bit offset */
|
||||
params->ip.ofs3 = 24; /* Alpha bit offset */
|
||||
params->ip.wid0 = 7; /* Red bit width - 1 */
|
||||
params->ip.wid1 = 7; /* Green bit width - 1 */
|
||||
params->ip.wid2 = 7; /* Blue bit width - 1 */
|
||||
break;
|
||||
default:
|
||||
printf("mx3fb: Pixel format not supported!\n");
|
||||
break;
|
||||
}
|
||||
|
||||
params->pp.nsb = 1;
|
||||
}
|
||||
|
||||
static void ipu_ch_param_set_buffer(union chan_param_mem *params,
|
||||
void *buf0, void *buf1)
|
||||
{
|
||||
params->pp.eba0 = (u32)buf0;
|
||||
params->pp.eba1 = (u32)buf1;
|
||||
}
|
||||
|
||||
static void ipu_write_param_mem(uint32_t addr, uint32_t *data,
|
||||
uint32_t num_words)
|
||||
{
|
||||
for (; num_words > 0; num_words--) {
|
||||
writel(addr, IPU_IMA_ADDR);
|
||||
writel(*data++, IPU_IMA_DATA);
|
||||
addr++;
|
||||
if ((addr & 0x7) == 5) {
|
||||
addr &= ~0x7; /* set to word 0 */
|
||||
addr += 8; /* increment to next row */
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static uint32_t dma_param_addr(enum ipu_channel channel)
|
||||
{
|
||||
/* Channel Parameter Memory */
|
||||
return 0x10000 | (channel << 4);
|
||||
}
|
||||
|
||||
static void ipu_init_channel_buffer(enum ipu_channel channel, void *fbmem)
|
||||
{
|
||||
union chan_param_mem params = {};
|
||||
uint32_t reg;
|
||||
uint32_t stride_bytes;
|
||||
|
||||
stride_bytes = (panel.plnSizeX * panel.gdfBytesPP + 3) & ~3;
|
||||
|
||||
debug("%s(channel=%d, fbmem=%p)\n", __func__, channel, fbmem);
|
||||
|
||||
/* Build parameter memory data for DMA channel */
|
||||
ipu_ch_param_set_size(¶ms, panel.gdfIndex,
|
||||
panel.plnSizeX, panel.plnSizeY, stride_bytes);
|
||||
ipu_ch_param_set_buffer(¶ms, fbmem, NULL);
|
||||
params.pp.bam = 0;
|
||||
/* Some channels (rotation) have restriction on burst length */
|
||||
|
||||
switch (channel) {
|
||||
case IDMAC_SDC_0:
|
||||
/* In original code only IPU_PIX_FMT_RGB565 was setting burst */
|
||||
params.pp.npb = 16 - 1;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
ipu_write_param_mem(dma_param_addr(channel), (uint32_t *)¶ms, 10);
|
||||
|
||||
/* Disable double-buffering */
|
||||
reg = readl(IPU_CHA_DB_MODE_SEL);
|
||||
reg &= ~(1UL << channel);
|
||||
writel(reg, IPU_CHA_DB_MODE_SEL);
|
||||
}
|
||||
|
||||
static void ipu_channel_set_priority(enum ipu_channel channel,
|
||||
int prio)
|
||||
{
|
||||
u32 reg = readl(IDMAC_CHA_PRI);
|
||||
|
||||
if (prio)
|
||||
reg |= 1UL << channel;
|
||||
else
|
||||
reg &= ~(1UL << channel);
|
||||
|
||||
writel(reg, IDMAC_CHA_PRI);
|
||||
}
|
||||
|
||||
/*
|
||||
* ipu_enable_channel() - enable an IPU channel.
|
||||
* @channel: channel ID.
|
||||
* @return: 0 on success or negative error code on failure.
|
||||
*/
|
||||
static int ipu_enable_channel(enum ipu_channel channel)
|
||||
{
|
||||
uint32_t reg;
|
||||
|
||||
/* Reset to buffer 0 */
|
||||
writel(1UL << channel, IPU_CHA_CUR_BUF);
|
||||
|
||||
switch (channel) {
|
||||
case IDMAC_SDC_0:
|
||||
ipu_channel_set_priority(channel, 1);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
reg = readl(IDMAC_CHA_EN);
|
||||
writel(reg | (1UL << channel), IDMAC_CHA_EN);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ipu_update_channel_buffer(enum ipu_channel channel, void *buf)
|
||||
{
|
||||
uint32_t reg;
|
||||
|
||||
reg = readl(IPU_CHA_BUF0_RDY);
|
||||
if (reg & (1UL << channel))
|
||||
return -EACCES;
|
||||
|
||||
/* 44.3.3.1.9 - Row Number 1 (WORD1, offset 0) */
|
||||
writel(dma_param_addr(channel) + 0x0008UL, IPU_IMA_ADDR);
|
||||
writel((u32)buf, IPU_IMA_DATA);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int idmac_tx_submit(enum ipu_channel channel, void *buf)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ipu_init_channel_buffer(channel, buf);
|
||||
|
||||
|
||||
/* ipu_idmac.c::ipu_submit_channel_buffers() */
|
||||
ret = ipu_update_channel_buffer(channel, buf);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
/* ipu_idmac.c::ipu_select_buffer() */
|
||||
/* Mark buffer 0 as ready. */
|
||||
writel(1UL << channel, IPU_CHA_BUF0_RDY);
|
||||
|
||||
|
||||
ret = ipu_enable_channel(channel);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void sdc_enable_channel(void *fbmem)
|
||||
{
|
||||
int ret;
|
||||
u32 reg;
|
||||
|
||||
ret = idmac_tx_submit(IDMAC_SDC_0, fbmem);
|
||||
|
||||
/* mx3fb.c::sdc_fb_init() */
|
||||
if (ret >= 0) {
|
||||
reg = readl(SDC_COM_CONF);
|
||||
writel(reg | SDC_COM_BG_EN, SDC_COM_CONF);
|
||||
}
|
||||
|
||||
/*
|
||||
* Attention! Without this msleep the channel keeps generating
|
||||
* interrupts. Next sdc_set_brightness() is going to be called
|
||||
* from mx3fb_blank().
|
||||
*/
|
||||
udelay(2000);
|
||||
}
|
||||
|
||||
/*
|
||||
* mx3fb_set_par() - set framebuffer parameters and change the operating mode.
|
||||
* @return: 0 on success or negative error code on failure.
|
||||
* TODO: currently only 666 and TFT as DI setup supported
|
||||
*/
|
||||
static int mx3fb_set_par(void)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = sdc_init_panel(panel.plnSizeX, panel.plnSizeY,
|
||||
IPU_PIX_FMT_RGB666, IPU_PANEL_TFT);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
writel((mode->left_margin << 16) | mode->upper_margin, SDC_BG_POS);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void ll_disp3_enable(void *base)
|
||||
{
|
||||
u32 reg;
|
||||
|
||||
debug("%s(base=0x%x)\n", __func__, (u32) base);
|
||||
/* pcm037.c::mxc_board_init() */
|
||||
|
||||
/* Display Interface #3 */
|
||||
mx31_gpio_mux(IOMUX_MODE_L(MX31_PIN_LD0, MUX_CTL_FUNC));
|
||||
mx31_gpio_mux(IOMUX_MODE_L(MX31_PIN_LD1, MUX_CTL_FUNC));
|
||||
mx31_gpio_mux(IOMUX_MODE_L(MX31_PIN_LD2, MUX_CTL_FUNC));
|
||||
mx31_gpio_mux(IOMUX_MODE_L(MX31_PIN_LD3, MUX_CTL_FUNC));
|
||||
mx31_gpio_mux(IOMUX_MODE_L(MX31_PIN_LD4, MUX_CTL_FUNC));
|
||||
mx31_gpio_mux(IOMUX_MODE_L(MX31_PIN_LD5, MUX_CTL_FUNC));
|
||||
mx31_gpio_mux(IOMUX_MODE_L(MX31_PIN_LD6, MUX_CTL_FUNC));
|
||||
mx31_gpio_mux(IOMUX_MODE_L(MX31_PIN_LD7, MUX_CTL_FUNC));
|
||||
mx31_gpio_mux(IOMUX_MODE_L(MX31_PIN_LD8, MUX_CTL_FUNC));
|
||||
mx31_gpio_mux(IOMUX_MODE_L(MX31_PIN_LD9, MUX_CTL_FUNC));
|
||||
mx31_gpio_mux(IOMUX_MODE_L(MX31_PIN_LD10, MUX_CTL_FUNC));
|
||||
mx31_gpio_mux(IOMUX_MODE_L(MX31_PIN_LD11, MUX_CTL_FUNC));
|
||||
mx31_gpio_mux(IOMUX_MODE_L(MX31_PIN_LD12, MUX_CTL_FUNC));
|
||||
mx31_gpio_mux(IOMUX_MODE_L(MX31_PIN_LD13, MUX_CTL_FUNC));
|
||||
mx31_gpio_mux(IOMUX_MODE_L(MX31_PIN_LD14, MUX_CTL_FUNC));
|
||||
mx31_gpio_mux(IOMUX_MODE_L(MX31_PIN_LD15, MUX_CTL_FUNC));
|
||||
mx31_gpio_mux(IOMUX_MODE_L(MX31_PIN_LD16, MUX_CTL_FUNC));
|
||||
mx31_gpio_mux(IOMUX_MODE_L(MX31_PIN_LD17, MUX_CTL_FUNC));
|
||||
mx31_gpio_mux(IOMUX_MODE_L(MX31_PIN_VSYNC3, MUX_CTL_FUNC));
|
||||
mx31_gpio_mux(IOMUX_MODE_L(MX31_PIN_HSYNC, MUX_CTL_FUNC));
|
||||
mx31_gpio_mux(IOMUX_MODE_L(MX31_PIN_FPSHIFT, MUX_CTL_FUNC));
|
||||
mx31_gpio_mux(IOMUX_MODE_L(MX31_PIN_DRDY0, MUX_CTL_FUNC));
|
||||
mx31_gpio_mux(IOMUX_MODE_L(MX31_PIN_D3_REV, MUX_CTL_FUNC));
|
||||
mx31_gpio_mux(IOMUX_MODE_L(MX31_PIN_CONTRAST, MUX_CTL_FUNC));
|
||||
mx31_gpio_mux(IOMUX_MODE_L(MX31_PIN_D3_SPL, MUX_CTL_FUNC));
|
||||
mx31_gpio_mux(IOMUX_MODE_L(MX31_PIN_D3_CLS, MUX_CTL_FUNC));
|
||||
|
||||
|
||||
/* ipu_idmac.c::ipu_probe() */
|
||||
|
||||
/* Start the clock */
|
||||
__REG(CCM_CGR1) = __REG(CCM_CGR1) | (3 << 22);
|
||||
|
||||
|
||||
/* ipu_idmac.c::ipu_idmac_init() */
|
||||
|
||||
/* Service request counter to maximum - shouldn't be needed */
|
||||
writel(0x00000070, IDMAC_CONF);
|
||||
|
||||
|
||||
/* ipu_idmac.c::ipu_init_channel() */
|
||||
|
||||
/* Enable IPU sub modules */
|
||||
reg = readl(IPU_CONF) | IPU_CONF_SDC_EN | IPU_CONF_DI_EN;
|
||||
writel(reg, IPU_CONF);
|
||||
|
||||
|
||||
/* mx3fb.c::init_fb_chan() */
|
||||
|
||||
/* set Display Interface clock period */
|
||||
writel(0x00100010L, DI_HSP_CLK_PER);
|
||||
/* Might need to trigger HSP clock change - see 44.3.3.8.5 */
|
||||
|
||||
|
||||
/* mx3fb.c::sdc_set_brightness() */
|
||||
|
||||
/* This might be board-specific */
|
||||
writel(0x03000000UL | 255 << 16, SDC_PWM_CTRL);
|
||||
|
||||
|
||||
/* mx3fb.c::sdc_set_global_alpha() */
|
||||
|
||||
/* Use global - not per-pixel - Alpha-blending */
|
||||
reg = readl(SDC_GW_CTRL) & 0x00FFFFFFL;
|
||||
writel(reg | ((uint32_t) 0xff << 24), SDC_GW_CTRL);
|
||||
|
||||
reg = readl(SDC_COM_CONF);
|
||||
writel(reg | SDC_COM_GLB_A, SDC_COM_CONF);
|
||||
|
||||
|
||||
/* mx3fb.c::sdc_set_color_key() */
|
||||
|
||||
/* Disable colour-keying for background */
|
||||
reg = readl(SDC_COM_CONF) &
|
||||
~(SDC_COM_GWSEL | SDC_COM_KEY_COLOR_G);
|
||||
writel(reg, SDC_COM_CONF);
|
||||
|
||||
|
||||
mx3fb_set_par();
|
||||
|
||||
sdc_enable_channel(base);
|
||||
|
||||
/*
|
||||
* Linux driver calls sdc_set_brightness() here again,
|
||||
* once is enough for us
|
||||
*/
|
||||
debug("%s() done\n", __func__);
|
||||
}
|
||||
|
||||
/* ------------------------ public part ------------------- */
|
||||
ulong calc_fbsize(void)
|
||||
{
|
||||
return panel.plnSizeX * panel.plnSizeY * panel.gdfBytesPP;
|
||||
}
|
||||
|
||||
/*
|
||||
* The current implementation is only tested for GDF_16BIT_565RGB!
|
||||
* It was switched from the original CONFIG_LCD setup to CONFIG_VIDEO,
|
||||
* because the lcd code seemed loaded with color table stuff, that
|
||||
* does not relate to most modern TFTs. cfb_console.c looks more
|
||||
* straight forward.
|
||||
* This is the environment setting for the original setup
|
||||
* "unknown=video=ctfb:x:240,y:320,depth:16,mode:0,pclk:185925,le:9,ri:17,
|
||||
* up:7,lo:10,hs:1,vs:1,sync:100663296,vmode:0"
|
||||
* "videomode=unknown"
|
||||
*
|
||||
* Settings for VBEST VGG322403 display:
|
||||
* "videomode=video=ctfb:x:320,y:240,depth:16,mode:0,pclk:156000,
|
||||
* "le:20,ri:68,up:7,lo:29,hs:30,vs:3,sync:100663296,vmode:0"
|
||||
*
|
||||
* Settings for COM57H5M10XRC display:
|
||||
* "videomode=video=ctfb:x:640,y:480,depth:16,mode:0,pclk:40000,
|
||||
* "le:120,ri:40,up:35,lo:10,hs:30,vs:3,sync:100663296,vmode:0"
|
||||
*/
|
||||
void *video_hw_init(void)
|
||||
{
|
||||
char *penv;
|
||||
u32 memsize;
|
||||
unsigned long t1, hsynch, vsynch;
|
||||
int bits_per_pixel, i, tmp, videomode;
|
||||
|
||||
tmp = 0;
|
||||
|
||||
puts("Video: ");
|
||||
|
||||
videomode = CONFIG_SYS_DEFAULT_VIDEO_MODE;
|
||||
/* get video mode via environment */
|
||||
penv = getenv("videomode");
|
||||
if (penv) {
|
||||
/* decide if it is a string */
|
||||
if (penv[0] <= '9') {
|
||||
videomode = (int) simple_strtoul(penv, NULL, 16);
|
||||
tmp = 1;
|
||||
}
|
||||
} else {
|
||||
tmp = 1;
|
||||
}
|
||||
if (tmp) {
|
||||
/* parameter are vesa modes */
|
||||
/* search params */
|
||||
for (i = 0; i < VESA_MODES_COUNT; i++) {
|
||||
if (vesa_modes[i].vesanr == videomode)
|
||||
break;
|
||||
}
|
||||
if (i == VESA_MODES_COUNT) {
|
||||
printf("No VESA Mode found, switching to mode 0x%x ",
|
||||
CONFIG_SYS_DEFAULT_VIDEO_MODE);
|
||||
i = 0;
|
||||
}
|
||||
mode = (struct ctfb_res_modes *)
|
||||
&res_mode_init[vesa_modes[i].resindex];
|
||||
bits_per_pixel = vesa_modes[i].bits_per_pixel;
|
||||
} else {
|
||||
mode = (struct ctfb_res_modes *) &var_mode;
|
||||
bits_per_pixel = video_get_params(mode, penv);
|
||||
}
|
||||
|
||||
/* calculate hsynch and vsynch freq (info only) */
|
||||
t1 = (mode->left_margin + mode->xres +
|
||||
mode->right_margin + mode->hsync_len) / 8;
|
||||
t1 *= 8;
|
||||
t1 *= mode->pixclock;
|
||||
t1 /= 1000;
|
||||
hsynch = 1000000000L / t1;
|
||||
t1 *= (mode->upper_margin + mode->yres +
|
||||
mode->lower_margin + mode->vsync_len);
|
||||
t1 /= 1000;
|
||||
vsynch = 1000000000L / t1;
|
||||
|
||||
/* fill in Graphic device struct */
|
||||
sprintf(panel.modeIdent, "%dx%dx%d %ldkHz %ldHz",
|
||||
mode->xres, mode->yres,
|
||||
bits_per_pixel, (hsynch / 1000), (vsynch / 1000));
|
||||
printf("%s\n", panel.modeIdent);
|
||||
panel.winSizeX = mode->xres;
|
||||
panel.winSizeY = mode->yres;
|
||||
panel.plnSizeX = mode->xres;
|
||||
panel.plnSizeY = mode->yres;
|
||||
|
||||
switch (bits_per_pixel) {
|
||||
case 24:
|
||||
panel.gdfBytesPP = 4;
|
||||
panel.gdfIndex = GDF_32BIT_X888RGB;
|
||||
break;
|
||||
case 16:
|
||||
panel.gdfBytesPP = 2;
|
||||
panel.gdfIndex = GDF_16BIT_565RGB;
|
||||
break;
|
||||
default:
|
||||
panel.gdfBytesPP = 1;
|
||||
panel.gdfIndex = GDF__8BIT_INDEX;
|
||||
break;
|
||||
}
|
||||
|
||||
/* set up Hardware */
|
||||
memsize = calc_fbsize();
|
||||
|
||||
debug("%s() allocating %d bytes\n", __func__, memsize);
|
||||
|
||||
/* fill in missing Graphic device struct */
|
||||
panel.frameAdrs = (u32) malloc(memsize);
|
||||
if (panel.frameAdrs == 0) {
|
||||
printf("%s() malloc(%d) failed\n", __func__, memsize);
|
||||
return 0;
|
||||
}
|
||||
panel.memSize = memsize;
|
||||
|
||||
ll_disp3_enable((void *) panel.frameAdrs);
|
||||
memset((void *) panel.frameAdrs, 0, memsize);
|
||||
|
||||
debug("%s() done, framebuffer at 0x%x, size=%d cleared\n",
|
||||
__func__, panel.frameAdrs, memsize);
|
||||
|
||||
return (void *) &panel;
|
||||
}
|
||||
|
||||
void video_set_lut(unsigned int index, /* color number */
|
||||
unsigned char r, /* red */
|
||||
unsigned char g, /* green */
|
||||
unsigned char b /* blue */
|
||||
)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
|
@ -0,0 +1,609 @@
|
|||
/*
|
||||
* Porting to u-boot:
|
||||
*
|
||||
* (C) Copyright 2010
|
||||
* Stefano Babic, DENX Software Engineering, sbabic@denx.de
|
||||
*
|
||||
* MX51 Linux framebuffer:
|
||||
*
|
||||
* (C) Copyright 2004-2010 Freescale Semiconductor, Inc.
|
||||
*
|
||||
* See file CREDITS for list of people who contributed to this
|
||||
* project.
|
||||
*
|
||||
* 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 <common.h>
|
||||
#include <asm/errno.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/list.h>
|
||||
#include <linux/fb.h>
|
||||
#include <asm/io.h>
|
||||
#include <malloc.h>
|
||||
#include <video_fb.h>
|
||||
#include "videomodes.h"
|
||||
#include "ipu.h"
|
||||
#include "mxcfb.h"
|
||||
|
||||
static int mxcfb_map_video_memory(struct fb_info *fbi);
|
||||
static int mxcfb_unmap_video_memory(struct fb_info *fbi);
|
||||
|
||||
/* graphics setup */
|
||||
static GraphicDevice panel;
|
||||
static struct fb_videomode *gmode;
|
||||
static uint8_t gdisp;
|
||||
static uint32_t gpixfmt;
|
||||
|
||||
void fb_videomode_to_var(struct fb_var_screeninfo *var,
|
||||
const struct fb_videomode *mode)
|
||||
{
|
||||
var->xres = mode->xres;
|
||||
var->yres = mode->yres;
|
||||
var->xres_virtual = mode->xres;
|
||||
var->yres_virtual = mode->yres;
|
||||
var->xoffset = 0;
|
||||
var->yoffset = 0;
|
||||
var->pixclock = mode->pixclock;
|
||||
var->left_margin = mode->left_margin;
|
||||
var->right_margin = mode->right_margin;
|
||||
var->upper_margin = mode->upper_margin;
|
||||
var->lower_margin = mode->lower_margin;
|
||||
var->hsync_len = mode->hsync_len;
|
||||
var->vsync_len = mode->vsync_len;
|
||||
var->sync = mode->sync;
|
||||
var->vmode = mode->vmode & FB_VMODE_MASK;
|
||||
}
|
||||
|
||||
/*
|
||||
* Structure containing the MXC specific framebuffer information.
|
||||
*/
|
||||
struct mxcfb_info {
|
||||
int blank;
|
||||
ipu_channel_t ipu_ch;
|
||||
int ipu_di;
|
||||
u32 ipu_di_pix_fmt;
|
||||
unsigned char overlay;
|
||||
unsigned char alpha_chan_en;
|
||||
dma_addr_t alpha_phy_addr0;
|
||||
dma_addr_t alpha_phy_addr1;
|
||||
void *alpha_virt_addr0;
|
||||
void *alpha_virt_addr1;
|
||||
uint32_t alpha_mem_len;
|
||||
uint32_t cur_ipu_buf;
|
||||
uint32_t cur_ipu_alpha_buf;
|
||||
|
||||
u32 pseudo_palette[16];
|
||||
};
|
||||
|
||||
enum {
|
||||
BOTH_ON,
|
||||
SRC_ON,
|
||||
TGT_ON,
|
||||
BOTH_OFF
|
||||
};
|
||||
|
||||
static unsigned long default_bpp = 16;
|
||||
static unsigned char g_dp_in_use;
|
||||
static struct fb_info *mxcfb_info[3];
|
||||
static int ext_clk_used;
|
||||
|
||||
static uint32_t bpp_to_pixfmt(struct fb_info *fbi)
|
||||
{
|
||||
uint32_t pixfmt = 0;
|
||||
|
||||
debug("bpp_to_pixfmt: %d\n", fbi->var.bits_per_pixel);
|
||||
|
||||
if (fbi->var.nonstd)
|
||||
return fbi->var.nonstd;
|
||||
|
||||
switch (fbi->var.bits_per_pixel) {
|
||||
case 24:
|
||||
pixfmt = IPU_PIX_FMT_BGR24;
|
||||
break;
|
||||
case 32:
|
||||
pixfmt = IPU_PIX_FMT_BGR32;
|
||||
break;
|
||||
case 16:
|
||||
pixfmt = IPU_PIX_FMT_RGB565;
|
||||
break;
|
||||
}
|
||||
return pixfmt;
|
||||
}
|
||||
|
||||
/*
|
||||
* Set fixed framebuffer parameters based on variable settings.
|
||||
*
|
||||
* @param info framebuffer information pointer
|
||||
*/
|
||||
static int mxcfb_set_fix(struct fb_info *info)
|
||||
{
|
||||
struct fb_fix_screeninfo *fix = &info->fix;
|
||||
struct fb_var_screeninfo *var = &info->var;
|
||||
|
||||
fix->line_length = var->xres_virtual * var->bits_per_pixel / 8;
|
||||
|
||||
fix->type = FB_TYPE_PACKED_PIXELS;
|
||||
fix->accel = FB_ACCEL_NONE;
|
||||
fix->visual = FB_VISUAL_TRUECOLOR;
|
||||
fix->xpanstep = 1;
|
||||
fix->ypanstep = 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int setup_disp_channel1(struct fb_info *fbi)
|
||||
{
|
||||
ipu_channel_params_t params;
|
||||
struct mxcfb_info *mxc_fbi = (struct mxcfb_info *)fbi->par;
|
||||
|
||||
memset(¶ms, 0, sizeof(params));
|
||||
params.mem_dp_bg_sync.di = mxc_fbi->ipu_di;
|
||||
|
||||
debug("%s called\n", __func__);
|
||||
/*
|
||||
* Assuming interlaced means yuv output, below setting also
|
||||
* valid for mem_dc_sync. FG should have the same vmode as BG.
|
||||
*/
|
||||
if (fbi->var.vmode & FB_VMODE_INTERLACED) {
|
||||
params.mem_dp_bg_sync.interlaced = 1;
|
||||
params.mem_dp_bg_sync.out_pixel_fmt =
|
||||
IPU_PIX_FMT_YUV444;
|
||||
} else {
|
||||
if (mxc_fbi->ipu_di_pix_fmt) {
|
||||
params.mem_dp_bg_sync.out_pixel_fmt =
|
||||
mxc_fbi->ipu_di_pix_fmt;
|
||||
} else {
|
||||
params.mem_dp_bg_sync.out_pixel_fmt =
|
||||
IPU_PIX_FMT_RGB666;
|
||||
}
|
||||
}
|
||||
params.mem_dp_bg_sync.in_pixel_fmt = bpp_to_pixfmt(fbi);
|
||||
if (mxc_fbi->alpha_chan_en)
|
||||
params.mem_dp_bg_sync.alpha_chan_en = 1;
|
||||
|
||||
ipu_init_channel(mxc_fbi->ipu_ch, ¶ms);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int setup_disp_channel2(struct fb_info *fbi)
|
||||
{
|
||||
int retval = 0;
|
||||
struct mxcfb_info *mxc_fbi = (struct mxcfb_info *)fbi->par;
|
||||
|
||||
mxc_fbi->cur_ipu_buf = 1;
|
||||
if (mxc_fbi->alpha_chan_en)
|
||||
mxc_fbi->cur_ipu_alpha_buf = 1;
|
||||
|
||||
fbi->var.xoffset = fbi->var.yoffset = 0;
|
||||
|
||||
debug("%s: %x %d %d %d %lx %lx\n",
|
||||
__func__,
|
||||
mxc_fbi->ipu_ch,
|
||||
fbi->var.xres,
|
||||
fbi->var.yres,
|
||||
fbi->fix.line_length,
|
||||
fbi->fix.smem_start,
|
||||
fbi->fix.smem_start +
|
||||
(fbi->fix.line_length * fbi->var.yres));
|
||||
|
||||
retval = ipu_init_channel_buffer(mxc_fbi->ipu_ch, IPU_INPUT_BUFFER,
|
||||
bpp_to_pixfmt(fbi),
|
||||
fbi->var.xres, fbi->var.yres,
|
||||
fbi->fix.line_length,
|
||||
fbi->fix.smem_start +
|
||||
(fbi->fix.line_length * fbi->var.yres),
|
||||
fbi->fix.smem_start,
|
||||
0, 0);
|
||||
if (retval)
|
||||
printf("ipu_init_channel_buffer error %d\n", retval);
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
/*
|
||||
* Set framebuffer parameters and change the operating mode.
|
||||
*
|
||||
* @param info framebuffer information pointer
|
||||
*/
|
||||
static int mxcfb_set_par(struct fb_info *fbi)
|
||||
{
|
||||
int retval = 0;
|
||||
u32 mem_len;
|
||||
ipu_di_signal_cfg_t sig_cfg;
|
||||
struct mxcfb_info *mxc_fbi = (struct mxcfb_info *)fbi->par;
|
||||
uint32_t out_pixel_fmt;
|
||||
|
||||
ipu_disable_channel(mxc_fbi->ipu_ch);
|
||||
ipu_uninit_channel(mxc_fbi->ipu_ch);
|
||||
mxcfb_set_fix(fbi);
|
||||
|
||||
mem_len = fbi->var.yres_virtual * fbi->fix.line_length;
|
||||
if (!fbi->fix.smem_start || (mem_len > fbi->fix.smem_len)) {
|
||||
if (fbi->fix.smem_start)
|
||||
mxcfb_unmap_video_memory(fbi);
|
||||
|
||||
if (mxcfb_map_video_memory(fbi) < 0)
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
setup_disp_channel1(fbi);
|
||||
|
||||
memset(&sig_cfg, 0, sizeof(sig_cfg));
|
||||
if (fbi->var.vmode & FB_VMODE_INTERLACED) {
|
||||
sig_cfg.interlaced = 1;
|
||||
out_pixel_fmt = IPU_PIX_FMT_YUV444;
|
||||
} else {
|
||||
if (mxc_fbi->ipu_di_pix_fmt)
|
||||
out_pixel_fmt = mxc_fbi->ipu_di_pix_fmt;
|
||||
else
|
||||
out_pixel_fmt = IPU_PIX_FMT_RGB666;
|
||||
}
|
||||
if (fbi->var.vmode & FB_VMODE_ODD_FLD_FIRST) /* PAL */
|
||||
sig_cfg.odd_field_first = 1;
|
||||
if ((fbi->var.sync & FB_SYNC_EXT) || ext_clk_used)
|
||||
sig_cfg.ext_clk = 1;
|
||||
if (fbi->var.sync & FB_SYNC_HOR_HIGH_ACT)
|
||||
sig_cfg.Hsync_pol = 1;
|
||||
if (fbi->var.sync & FB_SYNC_VERT_HIGH_ACT)
|
||||
sig_cfg.Vsync_pol = 1;
|
||||
if (!(fbi->var.sync & FB_SYNC_CLK_LAT_FALL))
|
||||
sig_cfg.clk_pol = 1;
|
||||
if (fbi->var.sync & FB_SYNC_DATA_INVERT)
|
||||
sig_cfg.data_pol = 1;
|
||||
if (!(fbi->var.sync & FB_SYNC_OE_LOW_ACT))
|
||||
sig_cfg.enable_pol = 1;
|
||||
if (fbi->var.sync & FB_SYNC_CLK_IDLE_EN)
|
||||
sig_cfg.clkidle_en = 1;
|
||||
|
||||
debug("pixclock = %ul Hz\n",
|
||||
(u32) (PICOS2KHZ(fbi->var.pixclock) * 1000UL));
|
||||
|
||||
if (ipu_init_sync_panel(mxc_fbi->ipu_di,
|
||||
(PICOS2KHZ(fbi->var.pixclock)) * 1000UL,
|
||||
fbi->var.xres, fbi->var.yres,
|
||||
out_pixel_fmt,
|
||||
fbi->var.left_margin,
|
||||
fbi->var.hsync_len,
|
||||
fbi->var.right_margin,
|
||||
fbi->var.upper_margin,
|
||||
fbi->var.vsync_len,
|
||||
fbi->var.lower_margin,
|
||||
0, sig_cfg) != 0) {
|
||||
puts("mxcfb: Error initializing panel.\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
retval = setup_disp_channel2(fbi);
|
||||
if (retval)
|
||||
return retval;
|
||||
|
||||
if (mxc_fbi->blank == FB_BLANK_UNBLANK)
|
||||
ipu_enable_channel(mxc_fbi->ipu_ch);
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
/*
|
||||
* Check framebuffer variable parameters and adjust to valid values.
|
||||
*
|
||||
* @param var framebuffer variable parameters
|
||||
*
|
||||
* @param info framebuffer information pointer
|
||||
*/
|
||||
static int mxcfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
|
||||
{
|
||||
u32 vtotal;
|
||||
u32 htotal;
|
||||
|
||||
if (var->xres_virtual < var->xres)
|
||||
var->xres_virtual = var->xres;
|
||||
if (var->yres_virtual < var->yres)
|
||||
var->yres_virtual = var->yres;
|
||||
|
||||
if ((var->bits_per_pixel != 32) && (var->bits_per_pixel != 24) &&
|
||||
(var->bits_per_pixel != 16) && (var->bits_per_pixel != 8))
|
||||
var->bits_per_pixel = default_bpp;
|
||||
|
||||
switch (var->bits_per_pixel) {
|
||||
case 8:
|
||||
var->red.length = 3;
|
||||
var->red.offset = 5;
|
||||
var->red.msb_right = 0;
|
||||
|
||||
var->green.length = 3;
|
||||
var->green.offset = 2;
|
||||
var->green.msb_right = 0;
|
||||
|
||||
var->blue.length = 2;
|
||||
var->blue.offset = 0;
|
||||
var->blue.msb_right = 0;
|
||||
|
||||
var->transp.length = 0;
|
||||
var->transp.offset = 0;
|
||||
var->transp.msb_right = 0;
|
||||
break;
|
||||
case 16:
|
||||
var->red.length = 5;
|
||||
var->red.offset = 11;
|
||||
var->red.msb_right = 0;
|
||||
|
||||
var->green.length = 6;
|
||||
var->green.offset = 5;
|
||||
var->green.msb_right = 0;
|
||||
|
||||
var->blue.length = 5;
|
||||
var->blue.offset = 0;
|
||||
var->blue.msb_right = 0;
|
||||
|
||||
var->transp.length = 0;
|
||||
var->transp.offset = 0;
|
||||
var->transp.msb_right = 0;
|
||||
break;
|
||||
case 24:
|
||||
var->red.length = 8;
|
||||
var->red.offset = 16;
|
||||
var->red.msb_right = 0;
|
||||
|
||||
var->green.length = 8;
|
||||
var->green.offset = 8;
|
||||
var->green.msb_right = 0;
|
||||
|
||||
var->blue.length = 8;
|
||||
var->blue.offset = 0;
|
||||
var->blue.msb_right = 0;
|
||||
|
||||
var->transp.length = 0;
|
||||
var->transp.offset = 0;
|
||||
var->transp.msb_right = 0;
|
||||
break;
|
||||
case 32:
|
||||
var->red.length = 8;
|
||||
var->red.offset = 16;
|
||||
var->red.msb_right = 0;
|
||||
|
||||
var->green.length = 8;
|
||||
var->green.offset = 8;
|
||||
var->green.msb_right = 0;
|
||||
|
||||
var->blue.length = 8;
|
||||
var->blue.offset = 0;
|
||||
var->blue.msb_right = 0;
|
||||
|
||||
var->transp.length = 8;
|
||||
var->transp.offset = 24;
|
||||
var->transp.msb_right = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
if (var->pixclock < 1000) {
|
||||
htotal = var->xres + var->right_margin + var->hsync_len +
|
||||
var->left_margin;
|
||||
vtotal = var->yres + var->lower_margin + var->vsync_len +
|
||||
var->upper_margin;
|
||||
var->pixclock = (vtotal * htotal * 6UL) / 100UL;
|
||||
var->pixclock = KHZ2PICOS(var->pixclock);
|
||||
printf("pixclock set for 60Hz refresh = %u ps\n",
|
||||
var->pixclock);
|
||||
}
|
||||
|
||||
var->height = -1;
|
||||
var->width = -1;
|
||||
var->grayscale = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mxcfb_map_video_memory(struct fb_info *fbi)
|
||||
{
|
||||
if (fbi->fix.smem_len < fbi->var.yres_virtual * fbi->fix.line_length) {
|
||||
fbi->fix.smem_len = fbi->var.yres_virtual *
|
||||
fbi->fix.line_length;
|
||||
}
|
||||
|
||||
fbi->screen_base = (char *)malloc(fbi->fix.smem_len);
|
||||
fbi->fix.smem_start = (unsigned long)fbi->screen_base;
|
||||
if (fbi->screen_base == 0) {
|
||||
puts("Unable to allocate framebuffer memory\n");
|
||||
fbi->fix.smem_len = 0;
|
||||
fbi->fix.smem_start = 0;
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
debug("allocated fb @ paddr=0x%08X, size=%d.\n",
|
||||
(uint32_t) fbi->fix.smem_start, fbi->fix.smem_len);
|
||||
|
||||
fbi->screen_size = fbi->fix.smem_len;
|
||||
|
||||
/* Clear the screen */
|
||||
memset((char *)fbi->screen_base, 0, fbi->fix.smem_len);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mxcfb_unmap_video_memory(struct fb_info *fbi)
|
||||
{
|
||||
fbi->screen_base = 0;
|
||||
fbi->fix.smem_start = 0;
|
||||
fbi->fix.smem_len = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Initializes the framebuffer information pointer. After allocating
|
||||
* sufficient memory for the framebuffer structure, the fields are
|
||||
* filled with custom information passed in from the configurable
|
||||
* structures. This includes information such as bits per pixel,
|
||||
* color maps, screen width/height and RGBA offsets.
|
||||
*
|
||||
* @return Framebuffer structure initialized with our information
|
||||
*/
|
||||
static struct fb_info *mxcfb_init_fbinfo(void)
|
||||
{
|
||||
#define BYTES_PER_LONG 4
|
||||
#define PADDING (BYTES_PER_LONG - (sizeof(struct fb_info) % BYTES_PER_LONG))
|
||||
struct fb_info *fbi;
|
||||
struct mxcfb_info *mxcfbi;
|
||||
char *p;
|
||||
int size = sizeof(struct mxcfb_info) + PADDING +
|
||||
sizeof(struct fb_info);
|
||||
|
||||
debug("%s: %d %d %d %d\n",
|
||||
__func__,
|
||||
PADDING,
|
||||
size,
|
||||
sizeof(struct mxcfb_info),
|
||||
sizeof(struct fb_info));
|
||||
/*
|
||||
* Allocate sufficient memory for the fb structure
|
||||
*/
|
||||
|
||||
p = malloc(size);
|
||||
if (!p)
|
||||
return NULL;
|
||||
|
||||
memset(p, 0, size);
|
||||
|
||||
fbi = (struct fb_info *)p;
|
||||
fbi->par = p + sizeof(struct fb_info) + PADDING;
|
||||
|
||||
mxcfbi = (struct mxcfb_info *)fbi->par;
|
||||
debug("Framebuffer structures at: fbi=0x%x mxcfbi=0x%x\n",
|
||||
(unsigned int)fbi, (unsigned int)mxcfbi);
|
||||
|
||||
fbi->var.activate = FB_ACTIVATE_NOW;
|
||||
|
||||
fbi->flags = FBINFO_FLAG_DEFAULT;
|
||||
fbi->pseudo_palette = mxcfbi->pseudo_palette;
|
||||
|
||||
return fbi;
|
||||
}
|
||||
|
||||
/*
|
||||
* Probe routine for the framebuffer driver. It is called during the
|
||||
* driver binding process. The following functions are performed in
|
||||
* this routine: Framebuffer initialization, Memory allocation and
|
||||
* mapping, Framebuffer registration, IPU initialization.
|
||||
*
|
||||
* @return Appropriate error code to the kernel common code
|
||||
*/
|
||||
static int mxcfb_probe(u32 interface_pix_fmt, uint8_t disp,
|
||||
struct fb_videomode *mode)
|
||||
{
|
||||
struct fb_info *fbi;
|
||||
struct mxcfb_info *mxcfbi;
|
||||
int ret = 0;
|
||||
|
||||
/*
|
||||
* Initialize FB structures
|
||||
*/
|
||||
fbi = mxcfb_init_fbinfo();
|
||||
if (!fbi) {
|
||||
ret = -ENOMEM;
|
||||
goto err0;
|
||||
}
|
||||
mxcfbi = (struct mxcfb_info *)fbi->par;
|
||||
|
||||
if (!g_dp_in_use) {
|
||||
mxcfbi->ipu_ch = MEM_BG_SYNC;
|
||||
mxcfbi->blank = FB_BLANK_UNBLANK;
|
||||
} else {
|
||||
mxcfbi->ipu_ch = MEM_DC_SYNC;
|
||||
mxcfbi->blank = FB_BLANK_POWERDOWN;
|
||||
}
|
||||
|
||||
mxcfbi->ipu_di = disp;
|
||||
|
||||
ipu_disp_set_global_alpha(mxcfbi->ipu_ch, 1, 0x80);
|
||||
ipu_disp_set_color_key(mxcfbi->ipu_ch, 0, 0);
|
||||
strcpy(fbi->fix.id, "DISP3 BG");
|
||||
|
||||
g_dp_in_use = 1;
|
||||
|
||||
mxcfb_info[mxcfbi->ipu_di] = fbi;
|
||||
|
||||
/* Need dummy values until real panel is configured */
|
||||
|
||||
mxcfbi->ipu_di_pix_fmt = interface_pix_fmt;
|
||||
fb_videomode_to_var(&fbi->var, mode);
|
||||
fbi->var.bits_per_pixel = 16;
|
||||
fbi->fix.line_length = fbi->var.xres * (fbi->var.bits_per_pixel / 8);
|
||||
fbi->fix.smem_len = fbi->var.yres_virtual * fbi->fix.line_length;
|
||||
|
||||
mxcfb_check_var(&fbi->var, fbi);
|
||||
|
||||
/* Default Y virtual size is 2x panel size */
|
||||
fbi->var.yres_virtual = fbi->var.yres * 2;
|
||||
|
||||
mxcfb_set_fix(fbi);
|
||||
|
||||
/* alocate fb first */
|
||||
if (mxcfb_map_video_memory(fbi) < 0)
|
||||
return -ENOMEM;
|
||||
|
||||
mxcfb_set_par(fbi);
|
||||
|
||||
panel.winSizeX = mode->xres;
|
||||
panel.winSizeY = mode->yres;
|
||||
panel.plnSizeX = mode->xres;
|
||||
panel.plnSizeY = mode->yres;
|
||||
|
||||
panel.frameAdrs = (u32)fbi->screen_base;
|
||||
panel.memSize = fbi->screen_size;
|
||||
|
||||
panel.gdfBytesPP = 2;
|
||||
panel.gdfIndex = GDF_16BIT_565RGB;
|
||||
|
||||
ipu_dump_registers();
|
||||
|
||||
return 0;
|
||||
|
||||
err0:
|
||||
return ret;
|
||||
}
|
||||
|
||||
void *video_hw_init(void)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = ipu_probe();
|
||||
if (ret)
|
||||
puts("Error initializing IPU\n");
|
||||
|
||||
ret = mxcfb_probe(gpixfmt, gdisp, gmode);
|
||||
debug("Framebuffer at 0x%x\n", (unsigned int)panel.frameAdrs);
|
||||
|
||||
return (void *)&panel;
|
||||
}
|
||||
|
||||
void video_set_lut(unsigned int index, /* color number */
|
||||
unsigned char r, /* red */
|
||||
unsigned char g, /* green */
|
||||
unsigned char b /* blue */
|
||||
)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
int ipuv3_fb_init(struct fb_videomode *mode, uint8_t disp, uint32_t pixfmt)
|
||||
{
|
||||
gmode = mode;
|
||||
gdisp = disp;
|
||||
gpixfmt = pixfmt;
|
||||
|
||||
return 0;
|
||||
}
|
||||
68
common/package/boot/uboot-ipq40xx/src/drivers/video/mxcfb.h
Normal file
68
common/package/boot/uboot-ipq40xx/src/drivers/video/mxcfb.h
Normal file
|
|
@ -0,0 +1,68 @@
|
|||
/*
|
||||
* Porting to u-boot:
|
||||
*
|
||||
* (C) Copyright 2010
|
||||
* Stefano Babic, DENX Software Engineering, sbabic@denx.de
|
||||
*
|
||||
* Linux IPU driver for MX51:
|
||||
*
|
||||
* (C) Copyright 2004-2009 Freescale Semiconductor, Inc.
|
||||
*
|
||||
* See file CREDITS for list of people who contributed to this
|
||||
* project.
|
||||
*
|
||||
* 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
|
||||
*/
|
||||
|
||||
#ifndef __ASM_ARCH_MXCFB_H__
|
||||
#define __ASM_ARCH_MXCFB_H__
|
||||
|
||||
#define FB_SYNC_OE_LOW_ACT 0x80000000
|
||||
#define FB_SYNC_CLK_LAT_FALL 0x40000000
|
||||
#define FB_SYNC_DATA_INVERT 0x20000000
|
||||
#define FB_SYNC_CLK_IDLE_EN 0x10000000
|
||||
#define FB_SYNC_SHARP_MODE 0x08000000
|
||||
#define FB_SYNC_SWAP_RGB 0x04000000
|
||||
|
||||
struct mxcfb_gbl_alpha {
|
||||
int enable;
|
||||
int alpha;
|
||||
};
|
||||
|
||||
struct mxcfb_loc_alpha {
|
||||
int enable;
|
||||
int alpha_in_pixel;
|
||||
unsigned long alpha_phy_addr0;
|
||||
unsigned long alpha_phy_addr1;
|
||||
};
|
||||
|
||||
struct mxcfb_color_key {
|
||||
int enable;
|
||||
__u32 color_key;
|
||||
};
|
||||
|
||||
struct mxcfb_pos {
|
||||
__u16 x;
|
||||
__u16 y;
|
||||
};
|
||||
|
||||
struct mxcfb_gamma {
|
||||
int enable;
|
||||
int constk[16];
|
||||
int slopek[16];
|
||||
};
|
||||
|
||||
#endif
|
||||
168
common/package/boot/uboot-ipq40xx/src/drivers/video/omap3_dss.c
Normal file
168
common/package/boot/uboot-ipq40xx/src/drivers/video/omap3_dss.c
Normal file
|
|
@ -0,0 +1,168 @@
|
|||
/*
|
||||
* (C) Copyright 2010
|
||||
* Texas Instruments, <www.ti.com>
|
||||
* Syed Mohammed Khasim <khasim@ti.com>
|
||||
*
|
||||
* Referred to Linux Kernel DSS driver files for OMAP3 by
|
||||
* Tomi Valkeinen from drivers/video/omap2/dss/
|
||||
*
|
||||
* See file CREDITS for list of people who contributed to this
|
||||
* project.
|
||||
*
|
||||
* 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's version 2 and any
|
||||
* later version the License.
|
||||
*
|
||||
* 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 <common.h>
|
||||
#include <asm/io.h>
|
||||
#include <asm/arch/dss.h>
|
||||
#include <video_fb.h>
|
||||
|
||||
/* Configure VENC for a given Mode (NTSC / PAL) */
|
||||
void omap3_dss_venc_config(const struct venc_regs *venc_cfg,
|
||||
u32 height, u32 width)
|
||||
{
|
||||
struct venc_regs *venc = (struct venc_regs *) OMAP3_VENC_BASE;
|
||||
struct dss_regs *dss = (struct dss_regs *) OMAP3_DSS_BASE;
|
||||
struct dispc_regs *dispc = (struct dispc_regs *) OMAP3_DISPC_BASE;
|
||||
|
||||
writel(venc_cfg->status, &venc->status);
|
||||
writel(venc_cfg->f_control, &venc->f_control);
|
||||
writel(venc_cfg->vidout_ctrl, &venc->vidout_ctrl);
|
||||
writel(venc_cfg->sync_ctrl, &venc->sync_ctrl);
|
||||
writel(venc_cfg->llen, &venc->llen);
|
||||
writel(venc_cfg->flens, &venc->flens);
|
||||
writel(venc_cfg->hfltr_ctrl, &venc->hfltr_ctrl);
|
||||
writel(venc_cfg->cc_carr_wss_carr, &venc->cc_carr_wss_carr);
|
||||
writel(venc_cfg->c_phase, &venc->c_phase);
|
||||
writel(venc_cfg->gain_u, &venc->gain_u);
|
||||
writel(venc_cfg->gain_v, &venc->gain_v);
|
||||
writel(venc_cfg->gain_y, &venc->gain_y);
|
||||
writel(venc_cfg->black_level, &venc->black_level);
|
||||
writel(venc_cfg->blank_level, &venc->blank_level);
|
||||
writel(venc_cfg->x_color, &venc->x_color);
|
||||
writel(venc_cfg->m_control, &venc->m_control);
|
||||
writel(venc_cfg->bstamp_wss_data, &venc->bstamp_wss_data);
|
||||
writel(venc_cfg->s_carr, &venc->s_carr);
|
||||
writel(venc_cfg->line21, &venc->line21);
|
||||
writel(venc_cfg->ln_sel, &venc->ln_sel);
|
||||
writel(venc_cfg->l21__wc_ctl, &venc->l21__wc_ctl);
|
||||
writel(venc_cfg->htrigger_vtrigger, &venc->htrigger_vtrigger);
|
||||
writel(venc_cfg->savid__eavid, &venc->savid__eavid);
|
||||
writel(venc_cfg->flen__fal, &venc->flen__fal);
|
||||
writel(venc_cfg->lal__phase_reset, &venc->lal__phase_reset);
|
||||
writel(venc_cfg->hs_int_start_stop_x, &venc->hs_int_start_stop_x);
|
||||
writel(venc_cfg->hs_ext_start_stop_x, &venc->hs_ext_start_stop_x);
|
||||
writel(venc_cfg->vs_int_start_x, &venc->vs_int_start_x);
|
||||
writel(venc_cfg->vs_int_stop_x__vs_int_start_y,
|
||||
&venc->vs_int_stop_x__vs_int_start_y);
|
||||
writel(venc_cfg->vs_int_stop_y__vs_ext_start_x,
|
||||
&venc->vs_int_stop_y__vs_ext_start_x);
|
||||
writel(venc_cfg->vs_ext_stop_x__vs_ext_start_y,
|
||||
&venc->vs_ext_stop_x__vs_ext_start_y);
|
||||
writel(venc_cfg->vs_ext_stop_y, &venc->vs_ext_stop_y);
|
||||
writel(venc_cfg->avid_start_stop_x, &venc->avid_start_stop_x);
|
||||
writel(venc_cfg->avid_start_stop_y, &venc->avid_start_stop_y);
|
||||
writel(venc_cfg->fid_int_start_x__fid_int_start_y,
|
||||
&venc->fid_int_start_x__fid_int_start_y);
|
||||
writel(venc_cfg->fid_int_offset_y__fid_ext_start_x,
|
||||
&venc->fid_int_offset_y__fid_ext_start_x);
|
||||
writel(venc_cfg->fid_ext_start_y__fid_ext_offset_y,
|
||||
&venc->fid_ext_start_y__fid_ext_offset_y);
|
||||
writel(venc_cfg->tvdetgp_int_start_stop_x,
|
||||
&venc->tvdetgp_int_start_stop_x);
|
||||
writel(venc_cfg->tvdetgp_int_start_stop_y,
|
||||
&venc->tvdetgp_int_start_stop_y);
|
||||
writel(venc_cfg->gen_ctrl, &venc->gen_ctrl);
|
||||
writel(venc_cfg->output_control, &venc->output_control);
|
||||
writel(venc_cfg->dac_b__dac_c, &venc->dac_b__dac_c);
|
||||
|
||||
/* Configure DSS for VENC Settings */
|
||||
writel(VENC_CLK_ENABLE | DAC_DEMEN | DAC_POWERDN | VENC_OUT_SEL,
|
||||
&dss->control);
|
||||
|
||||
/* Configure height and width for Digital out */
|
||||
writel(height << DIG_LPP_SHIFT | width, &dispc->size_dig);
|
||||
}
|
||||
|
||||
/* Configure Panel Specific Parameters */
|
||||
void omap3_dss_panel_config(const struct panel_config *panel_cfg)
|
||||
{
|
||||
struct dispc_regs *dispc = (struct dispc_regs *) OMAP3_DISPC_BASE;
|
||||
struct dss_regs *dss = (struct dss_regs *) OMAP3_DSS_BASE;
|
||||
|
||||
writel(DSS_SOFTRESET, &dss->sysconfig);
|
||||
while (!(readl(&dss->sysstatus) & DSS_RESETDONE))
|
||||
;
|
||||
|
||||
writel(panel_cfg->timing_h, &dispc->timing_h);
|
||||
writel(panel_cfg->timing_v, &dispc->timing_v);
|
||||
writel(panel_cfg->pol_freq, &dispc->pol_freq);
|
||||
writel(panel_cfg->divisor, &dispc->divisor);
|
||||
writel(panel_cfg->lcd_size, &dispc->size_lcd);
|
||||
writel(panel_cfg->load_mode << FRAME_MODE_SHIFT, &dispc->config);
|
||||
writel(panel_cfg->panel_type << TFTSTN_SHIFT |
|
||||
panel_cfg->data_lines << DATALINES_SHIFT, &dispc->control);
|
||||
writel(panel_cfg->panel_color, &dispc->default_color0);
|
||||
writel((u32) panel_cfg->frame_buffer, &dispc->gfx_ba0);
|
||||
|
||||
if (!panel_cfg->frame_buffer)
|
||||
return;
|
||||
|
||||
writel(panel_cfg->load_mode << LOADMODE_SHIFT, &dispc->config);
|
||||
writel(8 << GFX_FORMAT_SHIFT | GFX_ENABLE, &dispc->gfx_attributes);
|
||||
writel(1, &dispc->gfx_row_inc);
|
||||
writel(1, &dispc->gfx_pixel_inc);
|
||||
writel(panel_cfg->lcd_size, &dispc->gfx_size);
|
||||
}
|
||||
|
||||
/* Enable LCD and DIGITAL OUT in DSS */
|
||||
void omap3_dss_enable(void)
|
||||
{
|
||||
struct dispc_regs *dispc = (struct dispc_regs *) OMAP3_DISPC_BASE;
|
||||
u32 l;
|
||||
|
||||
l = readl(&dispc->control);
|
||||
l |= LCD_ENABLE | GO_LCD | DIG_ENABLE | GO_DIG | GP_OUT0 | GP_OUT1;
|
||||
writel(l, &dispc->control);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_CFB_CONSOLE
|
||||
int __board_video_init(void)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
int board_video_init(void)
|
||||
__attribute__((weak, alias("__board_video_init")));
|
||||
|
||||
void *video_hw_init(void)
|
||||
{
|
||||
static GraphicDevice dssfb;
|
||||
GraphicDevice *pGD = &dssfb;
|
||||
struct dispc_regs *dispc = (struct dispc_regs *) OMAP3_DISPC_BASE;
|
||||
|
||||
if (board_video_init() || !readl(&dispc->gfx_ba0))
|
||||
return NULL;
|
||||
|
||||
pGD->winSizeX = (readl(&dispc->size_lcd) & 0x7FF) + 1;
|
||||
pGD->winSizeY = ((readl(&dispc->size_lcd) >> 16) & 0x7FF) + 1;
|
||||
pGD->gdfBytesPP = 4;
|
||||
pGD->gdfIndex = GDF_32BIT_X888RGB;
|
||||
pGD->frameAdrs = readl(&dispc->gfx_ba0);
|
||||
|
||||
return pGD;
|
||||
}
|
||||
#endif
|
||||
|
|
@ -0,0 +1,76 @@
|
|||
/*
|
||||
* Copyright (C) 2009
|
||||
* Guennadi Liakhovetski, DENX Software Engineering, <lg@denx.de>
|
||||
*
|
||||
* See file CREDITS for list of people who contributed to this
|
||||
* project.
|
||||
*
|
||||
* 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 <common.h>
|
||||
#include <spi.h>
|
||||
#include <s6e63d6.h>
|
||||
|
||||
/*
|
||||
* Each transfer is performed as:
|
||||
* 1. chip-select active
|
||||
* 2. send 8-bit start code
|
||||
* 3. send 16-bit data
|
||||
* 4. chip-select inactive
|
||||
*/
|
||||
static int send_word(struct s6e63d6 *data, u8 rs, u16 word)
|
||||
{
|
||||
/*
|
||||
* The start byte looks like (binary):
|
||||
* 01110<ID><RS><R/W>
|
||||
* RS is 0 for index or 1 for data, and R/W is 0 for write.
|
||||
*/
|
||||
u32 buf8 = 0x70 | data->id | (rs & 2);
|
||||
u32 buf16 = cpu_to_le16(word);
|
||||
u32 buf_in;
|
||||
int err;
|
||||
|
||||
err = spi_xfer(data->slave, 8, &buf8, &buf_in, SPI_XFER_BEGIN);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
return spi_xfer(data->slave, 16, &buf16, &buf_in, SPI_XFER_END);
|
||||
}
|
||||
|
||||
/* Index and param differ in Register Select bit */
|
||||
int s6e63d6_index(struct s6e63d6 *data, u8 idx)
|
||||
{
|
||||
return send_word(data, 0, idx);
|
||||
}
|
||||
|
||||
int s6e63d6_param(struct s6e63d6 *data, u16 param)
|
||||
{
|
||||
return send_word(data, 2, param);
|
||||
}
|
||||
|
||||
int s6e63d6_init(struct s6e63d6 *data)
|
||||
{
|
||||
if (data->id != 0 && data->id != 4) {
|
||||
printf("s6e63d6: invalid ID %u\n", data->id);
|
||||
return 1;
|
||||
}
|
||||
|
||||
data->slave = spi_setup_slave(data->bus, data->cs, 100000, SPI_MODE_3);
|
||||
if (!data->slave)
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
271
common/package/boot/uboot-ipq40xx/src/drivers/video/s6e8ax0.c
Normal file
271
common/package/boot/uboot-ipq40xx/src/drivers/video/s6e8ax0.c
Normal file
|
|
@ -0,0 +1,271 @@
|
|||
/*
|
||||
* Copyright (C) 2012 Samsung Electronics
|
||||
*
|
||||
* Author: Donghwa Lee <dh09.lee@samsung.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 <common.h>
|
||||
#include <asm/arch/mipi_dsim.h>
|
||||
|
||||
#include "exynos_mipi_dsi_lowlevel.h"
|
||||
#include "exynos_mipi_dsi_common.h"
|
||||
|
||||
static void s6e8ax0_panel_cond(struct mipi_dsim_device *dsim_dev)
|
||||
{
|
||||
struct mipi_dsim_master_ops *ops = dsim_dev->master_ops;
|
||||
int reverse = dsim_dev->dsim_lcd_dev->reverse_panel;
|
||||
const unsigned char data_to_send[] = {
|
||||
0xf8, 0x3d, 0x35, 0x00, 0x00, 0x00, 0x8d, 0x00, 0x4c,
|
||||
0x6e, 0x10, 0x27, 0x7d, 0x3f, 0x10, 0x00, 0x00, 0x20,
|
||||
0x04, 0x08, 0x6e, 0x00, 0x00, 0x00, 0x02, 0x08, 0x08,
|
||||
0x23, 0x23, 0xc0, 0xc8, 0x08, 0x48, 0xc1, 0x00, 0xc3,
|
||||
0xff, 0xff, 0xc8
|
||||
};
|
||||
|
||||
const unsigned char data_to_send_reverse[] = {
|
||||
0xf8, 0x19, 0x35, 0x00, 0x00, 0x00, 0x93, 0x00, 0x3c,
|
||||
0x7d, 0x08, 0x27, 0x7d, 0x3f, 0x00, 0x00, 0x00, 0x20,
|
||||
0x04, 0x08, 0x6e, 0x00, 0x00, 0x00, 0x02, 0x08, 0x08,
|
||||
0x23, 0x23, 0xc0, 0xc1, 0x01, 0x41, 0xc1, 0x00, 0xc1,
|
||||
0xf6, 0xf6, 0xc1
|
||||
};
|
||||
|
||||
if (reverse) {
|
||||
ops->cmd_write(dsim_dev, MIPI_DSI_DCS_LONG_WRITE,
|
||||
(unsigned int)data_to_send_reverse,
|
||||
ARRAY_SIZE(data_to_send_reverse));
|
||||
} else {
|
||||
ops->cmd_write(dsim_dev, MIPI_DSI_DCS_LONG_WRITE,
|
||||
(unsigned int)data_to_send, ARRAY_SIZE(data_to_send));
|
||||
}
|
||||
}
|
||||
|
||||
static void s6e8ax0_display_cond(struct mipi_dsim_device *dsim_dev)
|
||||
{
|
||||
struct mipi_dsim_master_ops *ops = dsim_dev->master_ops;
|
||||
const unsigned char data_to_send[] = {
|
||||
0xf2, 0x80, 0x03, 0x0d
|
||||
};
|
||||
|
||||
ops->cmd_write(dsim_dev, MIPI_DSI_DCS_LONG_WRITE,
|
||||
(unsigned int)data_to_send,
|
||||
ARRAY_SIZE(data_to_send));
|
||||
}
|
||||
|
||||
static void s6e8ax0_gamma_cond(struct mipi_dsim_device *dsim_dev)
|
||||
{
|
||||
struct mipi_dsim_master_ops *ops = dsim_dev->master_ops;
|
||||
/* 7500K 2.2 Set : 30cd */
|
||||
const unsigned char data_to_send[] = {
|
||||
0xfa, 0x01, 0x60, 0x10, 0x60, 0xf5, 0x00, 0xff, 0xad,
|
||||
0xaf, 0xba, 0xc3, 0xd8, 0xc5, 0x9f, 0xc6, 0x9e, 0xc1,
|
||||
0xdc, 0xc0, 0x00, 0x61, 0x00, 0x5a, 0x00, 0x74,
|
||||
};
|
||||
|
||||
ops->cmd_write(dsim_dev, MIPI_DSI_DCS_LONG_WRITE,
|
||||
(unsigned int)data_to_send,
|
||||
ARRAY_SIZE(data_to_send));
|
||||
}
|
||||
|
||||
static void s6e8ax0_gamma_update(struct mipi_dsim_device *dsim_dev)
|
||||
{
|
||||
struct mipi_dsim_master_ops *ops = dsim_dev->master_ops;
|
||||
|
||||
ops->cmd_write(dsim_dev, MIPI_DSI_DCS_SHORT_WRITE_PARAM, 0xf7, 0x3);
|
||||
}
|
||||
|
||||
static void s6e8ax0_etc_source_control(struct mipi_dsim_device *dsim_dev)
|
||||
{
|
||||
struct mipi_dsim_master_ops *ops = dsim_dev->master_ops;
|
||||
const unsigned char data_to_send[] = {
|
||||
0xf6, 0x00, 0x02, 0x00
|
||||
};
|
||||
|
||||
ops->cmd_write(dsim_dev, MIPI_DSI_DCS_LONG_WRITE,
|
||||
(unsigned int)data_to_send,
|
||||
ARRAY_SIZE(data_to_send));
|
||||
}
|
||||
|
||||
static void s6e8ax0_etc_pentile_control(struct mipi_dsim_device *dsim_dev)
|
||||
{
|
||||
struct mipi_dsim_master_ops *ops = dsim_dev->master_ops;
|
||||
const unsigned char data_to_send[] = {
|
||||
0xb6, 0x0c, 0x02, 0x03, 0x32, 0xff, 0x44, 0x44, 0xc0,
|
||||
0x00
|
||||
};
|
||||
|
||||
ops->cmd_write(dsim_dev, MIPI_DSI_DCS_LONG_WRITE,
|
||||
(unsigned int)data_to_send,
|
||||
ARRAY_SIZE(data_to_send));
|
||||
}
|
||||
|
||||
static void s6e8ax0_etc_mipi_control1(struct mipi_dsim_device *dsim_dev)
|
||||
{
|
||||
struct mipi_dsim_master_ops *ops = dsim_dev->master_ops;
|
||||
const unsigned char data_to_send[] = {
|
||||
0xe1, 0x10, 0x1c, 0x17, 0x08, 0x1d
|
||||
};
|
||||
|
||||
ops->cmd_write(dsim_dev, MIPI_DSI_DCS_LONG_WRITE,
|
||||
(unsigned int)data_to_send,
|
||||
ARRAY_SIZE(data_to_send));
|
||||
}
|
||||
|
||||
static void s6e8ax0_etc_mipi_control2(struct mipi_dsim_device *dsim_dev)
|
||||
{
|
||||
struct mipi_dsim_master_ops *ops = dsim_dev->master_ops;
|
||||
const unsigned char data_to_send[] = {
|
||||
0xe2, 0xed, 0x07, 0xc3, 0x13, 0x0d, 0x03
|
||||
};
|
||||
|
||||
ops->cmd_write(dsim_dev, MIPI_DSI_DCS_LONG_WRITE,
|
||||
(unsigned int)data_to_send,
|
||||
ARRAY_SIZE(data_to_send));
|
||||
}
|
||||
|
||||
static void s6e8ax0_etc_power_control(struct mipi_dsim_device *dsim_dev)
|
||||
{
|
||||
struct mipi_dsim_master_ops *ops = dsim_dev->master_ops;
|
||||
const unsigned char data_to_send[] = {
|
||||
0xf4, 0xcf, 0x0a, 0x12, 0x10, 0x19, 0x33, 0x02
|
||||
};
|
||||
|
||||
ops->cmd_write(dsim_dev, MIPI_DSI_DCS_LONG_WRITE,
|
||||
(unsigned int)data_to_send, ARRAY_SIZE(data_to_send));
|
||||
}
|
||||
|
||||
static void s6e8ax0_etc_mipi_control3(struct mipi_dsim_device *dsim_dev)
|
||||
{
|
||||
struct mipi_dsim_master_ops *ops = dsim_dev->master_ops;
|
||||
|
||||
ops->cmd_write(dsim_dev, MIPI_DSI_DCS_SHORT_WRITE_PARAM, 0xe3, 0x40);
|
||||
}
|
||||
|
||||
static void s6e8ax0_etc_mipi_control4(struct mipi_dsim_device *dsim_dev)
|
||||
{
|
||||
struct mipi_dsim_master_ops *ops = dsim_dev->master_ops;
|
||||
const unsigned char data_to_send[] = {
|
||||
0xe4, 0x00, 0x00, 0x14, 0x80, 0x00, 0x00, 0x00
|
||||
};
|
||||
|
||||
ops->cmd_write(dsim_dev, MIPI_DSI_DCS_LONG_WRITE,
|
||||
(unsigned int)data_to_send, ARRAY_SIZE(data_to_send));
|
||||
}
|
||||
|
||||
static void s6e8ax0_elvss_set(struct mipi_dsim_device *dsim_dev)
|
||||
{
|
||||
struct mipi_dsim_master_ops *ops = dsim_dev->master_ops;
|
||||
const unsigned char data_to_send[] = {
|
||||
0xb1, 0x04, 0x00
|
||||
};
|
||||
|
||||
ops->cmd_write(dsim_dev, MIPI_DSI_DCS_LONG_WRITE,
|
||||
(unsigned int)data_to_send,
|
||||
ARRAY_SIZE(data_to_send));
|
||||
}
|
||||
|
||||
static void s6e8ax0_display_on(struct mipi_dsim_device *dsim_dev)
|
||||
{
|
||||
struct mipi_dsim_master_ops *ops = dsim_dev->master_ops;
|
||||
|
||||
ops->cmd_write(dsim_dev,
|
||||
MIPI_DSI_DCS_SHORT_WRITE, 0x29, 0x00);
|
||||
}
|
||||
|
||||
static void s6e8ax0_sleep_out(struct mipi_dsim_device *dsim_dev)
|
||||
{
|
||||
struct mipi_dsim_master_ops *ops = dsim_dev->master_ops;
|
||||
|
||||
ops->cmd_write(dsim_dev,
|
||||
MIPI_DSI_DCS_SHORT_WRITE, 0x11, 0x00);
|
||||
}
|
||||
|
||||
static void s6e8ax0_apply_level1_key(struct mipi_dsim_device *dsim_dev)
|
||||
{
|
||||
struct mipi_dsim_master_ops *ops = dsim_dev->master_ops;
|
||||
const unsigned char data_to_send[] = {
|
||||
0xf0, 0x5a, 0x5a
|
||||
};
|
||||
|
||||
ops->cmd_write(dsim_dev, MIPI_DSI_DCS_LONG_WRITE,
|
||||
(unsigned int)data_to_send, ARRAY_SIZE(data_to_send));
|
||||
}
|
||||
|
||||
static void s6e8ax0_apply_mtp_key(struct mipi_dsim_device *dsim_dev)
|
||||
{
|
||||
struct mipi_dsim_master_ops *ops = dsim_dev->master_ops;
|
||||
const unsigned char data_to_send[] = {
|
||||
0xf1, 0x5a, 0x5a
|
||||
};
|
||||
|
||||
ops->cmd_write(dsim_dev, MIPI_DSI_DCS_LONG_WRITE,
|
||||
(unsigned int)data_to_send, ARRAY_SIZE(data_to_send));
|
||||
}
|
||||
|
||||
static void s6e8ax0_panel_init(struct mipi_dsim_device *dsim_dev)
|
||||
{
|
||||
/*
|
||||
* in case of setting gamma and panel condition at first,
|
||||
* it shuold be setting like below.
|
||||
* set_gamma() -> set_panel_condition()
|
||||
*/
|
||||
|
||||
s6e8ax0_apply_level1_key(dsim_dev);
|
||||
s6e8ax0_apply_mtp_key(dsim_dev);
|
||||
|
||||
s6e8ax0_sleep_out(dsim_dev);
|
||||
mdelay(5);
|
||||
s6e8ax0_panel_cond(dsim_dev);
|
||||
s6e8ax0_display_cond(dsim_dev);
|
||||
s6e8ax0_gamma_cond(dsim_dev);
|
||||
s6e8ax0_gamma_update(dsim_dev);
|
||||
|
||||
s6e8ax0_etc_source_control(dsim_dev);
|
||||
s6e8ax0_elvss_set(dsim_dev);
|
||||
s6e8ax0_etc_pentile_control(dsim_dev);
|
||||
s6e8ax0_etc_mipi_control1(dsim_dev);
|
||||
s6e8ax0_etc_mipi_control2(dsim_dev);
|
||||
s6e8ax0_etc_power_control(dsim_dev);
|
||||
s6e8ax0_etc_mipi_control3(dsim_dev);
|
||||
s6e8ax0_etc_mipi_control4(dsim_dev);
|
||||
}
|
||||
|
||||
static int s6e8ax0_panel_set(struct mipi_dsim_device *dsim_dev)
|
||||
{
|
||||
s6e8ax0_panel_init(dsim_dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void s6e8ax0_display_enable(struct mipi_dsim_device *dsim_dev)
|
||||
{
|
||||
s6e8ax0_display_on(dsim_dev);
|
||||
}
|
||||
|
||||
static struct mipi_dsim_lcd_driver s6e8ax0_dsim_ddi_driver = {
|
||||
.name = "s6e8ax0",
|
||||
.id = -1,
|
||||
|
||||
.mipi_panel_init = s6e8ax0_panel_set,
|
||||
.mipi_display_on = s6e8ax0_display_enable,
|
||||
};
|
||||
|
||||
void s6e8ax0_init(void)
|
||||
{
|
||||
exynos_mipi_dsi_register_lcd_driver(&s6e8ax0_dsim_ddi_driver);
|
||||
}
|
||||
307
common/package/boot/uboot-ipq40xx/src/drivers/video/sed13806.c
Normal file
307
common/package/boot/uboot-ipq40xx/src/drivers/video/sed13806.c
Normal file
|
|
@ -0,0 +1,307 @@
|
|||
/*
|
||||
* (C) Copyright 2002
|
||||
* Stäubli Faverges - <www.staubli.com>
|
||||
* Pierre AUBERT p.aubert@staubli.com
|
||||
*
|
||||
* See file CREDITS for list of people who contributed to this
|
||||
* project.
|
||||
*
|
||||
* 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
|
||||
*/
|
||||
/* Video support for Epson SED13806 chipset */
|
||||
|
||||
#include <common.h>
|
||||
|
||||
#include <video_fb.h>
|
||||
#include <sed13806.h>
|
||||
|
||||
#define readByte(ptrReg) \
|
||||
*(volatile unsigned char *)(sed13806.isaBase + ptrReg)
|
||||
|
||||
#define writeByte(ptrReg,value) \
|
||||
*(volatile unsigned char *)(sed13806.isaBase + ptrReg) = value
|
||||
|
||||
#ifdef CONFIG_TOTAL5200
|
||||
#define writeWord(ptrReg,value) \
|
||||
(*(volatile unsigned short *)(sed13806.isaBase + ptrReg) = value)
|
||||
#else
|
||||
#define writeWord(ptrReg,value) \
|
||||
(*(volatile unsigned short *)(sed13806.isaBase + ptrReg) = ((value >> 8 ) & 0xff) | ((value << 8) & 0xff00))
|
||||
#endif
|
||||
|
||||
GraphicDevice sed13806;
|
||||
|
||||
/*-----------------------------------------------------------------------------
|
||||
* EpsonSetRegs --
|
||||
*-----------------------------------------------------------------------------
|
||||
*/
|
||||
static void EpsonSetRegs (void)
|
||||
{
|
||||
/* the content of the chipset register depends on the board (clocks, ...)*/
|
||||
const S1D_REGS *preg = board_get_regs ();
|
||||
while (preg -> Index) {
|
||||
writeByte (preg -> Index, preg -> Value);
|
||||
preg ++;
|
||||
}
|
||||
}
|
||||
|
||||
/*-----------------------------------------------------------------------------
|
||||
* video_hw_init --
|
||||
*-----------------------------------------------------------------------------
|
||||
*/
|
||||
void *video_hw_init (void)
|
||||
{
|
||||
unsigned int *vm, i;
|
||||
|
||||
memset (&sed13806, 0, sizeof (GraphicDevice));
|
||||
|
||||
/* Initialization of the access to the graphic chipset
|
||||
Retreive base address of the chipset
|
||||
(see board/RPXClassic/eccx.c) */
|
||||
if ((sed13806.isaBase = board_video_init ()) == 0) {
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
sed13806.frameAdrs = sed13806.isaBase + FRAME_BUFFER_OFFSET;
|
||||
sed13806.winSizeX = board_get_width ();
|
||||
sed13806.winSizeY = board_get_height ();
|
||||
|
||||
#if defined(CONFIG_VIDEO_SED13806_8BPP)
|
||||
sed13806.gdfIndex = GDF__8BIT_INDEX;
|
||||
sed13806.gdfBytesPP = 1;
|
||||
|
||||
#elif defined(CONFIG_VIDEO_SED13806_16BPP)
|
||||
sed13806.gdfIndex = GDF_16BIT_565RGB;
|
||||
sed13806.gdfBytesPP = 2;
|
||||
|
||||
#else
|
||||
#error Unsupported SED13806 BPP
|
||||
#endif
|
||||
|
||||
sed13806.memSize = sed13806.winSizeX * sed13806.winSizeY * sed13806.gdfBytesPP;
|
||||
|
||||
/* Load SED registers */
|
||||
EpsonSetRegs ();
|
||||
|
||||
/* (see board/RPXClassic/RPXClassic.c) */
|
||||
board_validate_screen (sed13806.isaBase);
|
||||
|
||||
/* Clear video memory */
|
||||
i = sed13806.memSize/4;
|
||||
vm = (unsigned int *)sed13806.frameAdrs;
|
||||
while(i--)
|
||||
*vm++ = 0;
|
||||
|
||||
|
||||
return (&sed13806);
|
||||
}
|
||||
/*-----------------------------------------------------------------------------
|
||||
* Epson_wait_idle -- Wait for hardware to become idle
|
||||
*-----------------------------------------------------------------------------
|
||||
*/
|
||||
static void Epson_wait_idle (void)
|
||||
{
|
||||
while (readByte (BLT_CTRL0) & 0x80);
|
||||
|
||||
/* Read a word in the BitBLT memory area to shutdown the BitBLT engine */
|
||||
*(volatile unsigned short *)(sed13806.isaBase + BLT_REG);
|
||||
}
|
||||
|
||||
/*-----------------------------------------------------------------------------
|
||||
* video_hw_bitblt --
|
||||
*-----------------------------------------------------------------------------
|
||||
*/
|
||||
void video_hw_bitblt (
|
||||
unsigned int bpp, /* bytes per pixel */
|
||||
unsigned int src_x, /* source pos x */
|
||||
unsigned int src_y, /* source pos y */
|
||||
unsigned int dst_x, /* dest pos x */
|
||||
unsigned int dst_y, /* dest pos y */
|
||||
unsigned int dim_x, /* frame width */
|
||||
unsigned int dim_y /* frame height */
|
||||
)
|
||||
{
|
||||
register GraphicDevice *pGD = (GraphicDevice *)&sed13806;
|
||||
unsigned long srcAddr, dstAddr;
|
||||
unsigned int stride = bpp * pGD -> winSizeX;
|
||||
|
||||
srcAddr = (src_y * stride) + (src_x * bpp);
|
||||
dstAddr = (dst_y * stride) + (dst_x * bpp);
|
||||
|
||||
Epson_wait_idle ();
|
||||
|
||||
writeByte(BLT_ROP,0x0C); /* source */
|
||||
writeByte(BLT_OP,0x02);/* move blit in positive direction with ROP */
|
||||
writeWord(BLT_MEM_OFF0, stride / 2);
|
||||
if (pGD -> gdfIndex == GDF__8BIT_INDEX) {
|
||||
writeByte(BLT_CTRL1,0x00);
|
||||
}
|
||||
else {
|
||||
writeByte(BLT_CTRL1,0x01);
|
||||
}
|
||||
|
||||
writeWord(BLT_WIDTH0,(dim_x - 1));
|
||||
writeWord(BLT_HEIGHT0,(dim_y - 1));
|
||||
|
||||
/* set up blit registers */
|
||||
writeByte(BLT_SRC_ADDR0,srcAddr);
|
||||
writeByte(BLT_SRC_ADDR1,srcAddr>>8);
|
||||
writeByte(BLT_SRC_ADDR2,srcAddr>>16);
|
||||
|
||||
writeByte(BLT_DST_ADDR0,dstAddr);
|
||||
writeByte(BLT_DST_ADDR1,dstAddr>>8);
|
||||
writeByte(BLT_DST_ADDR2,dstAddr>>16);
|
||||
|
||||
/* Engage the blt engine */
|
||||
/* rectangular region for src and dst */
|
||||
writeByte(BLT_CTRL0,0x80);
|
||||
|
||||
/* wait untill current blits finished */
|
||||
Epson_wait_idle ();
|
||||
}
|
||||
/*-----------------------------------------------------------------------------
|
||||
* video_hw_rectfill --
|
||||
*-----------------------------------------------------------------------------
|
||||
*/
|
||||
void video_hw_rectfill (
|
||||
unsigned int bpp, /* bytes per pixel */
|
||||
unsigned int dst_x, /* dest pos x */
|
||||
unsigned int dst_y, /* dest pos y */
|
||||
unsigned int dim_x, /* frame width */
|
||||
unsigned int dim_y, /* frame height */
|
||||
unsigned int color /* fill color */
|
||||
)
|
||||
{
|
||||
register GraphicDevice *pGD = (GraphicDevice *)&sed13806;
|
||||
unsigned long dstAddr;
|
||||
unsigned int stride = bpp * pGD -> winSizeX;
|
||||
|
||||
dstAddr = (dst_y * stride) + (dst_x * bpp);
|
||||
|
||||
Epson_wait_idle ();
|
||||
|
||||
/* set up blit registers */
|
||||
writeByte(BLT_DST_ADDR0,dstAddr);
|
||||
writeByte(BLT_DST_ADDR1,dstAddr>>8);
|
||||
writeByte(BLT_DST_ADDR2,dstAddr>>16);
|
||||
|
||||
writeWord(BLT_WIDTH0,(dim_x - 1));
|
||||
writeWord(BLT_HEIGHT0,(dim_y - 1));
|
||||
writeWord(BLT_FGCOLOR0,color);
|
||||
|
||||
writeByte(BLT_OP,0x0C); /* solid fill */
|
||||
writeWord(BLT_MEM_OFF0,stride / 2);
|
||||
|
||||
if (pGD -> gdfIndex == GDF__8BIT_INDEX) {
|
||||
writeByte(BLT_CTRL1,0x00);
|
||||
}
|
||||
else {
|
||||
writeByte(BLT_CTRL1,0x01);
|
||||
}
|
||||
|
||||
/* Engage the blt engine */
|
||||
/* rectangular region for src and dst */
|
||||
writeByte(BLT_CTRL0,0x80);
|
||||
|
||||
/* wait untill current blits finished */
|
||||
Epson_wait_idle ();
|
||||
}
|
||||
|
||||
/*-----------------------------------------------------------------------------
|
||||
* video_set_lut --
|
||||
*-----------------------------------------------------------------------------
|
||||
*/
|
||||
void video_set_lut (
|
||||
unsigned int index, /* color number */
|
||||
unsigned char r, /* red */
|
||||
unsigned char g, /* green */
|
||||
unsigned char b /* blue */
|
||||
)
|
||||
{
|
||||
writeByte(REG_LUT_ADDR, index );
|
||||
writeByte(REG_LUT_DATA, r);
|
||||
writeByte(REG_LUT_DATA, g);
|
||||
writeByte(REG_LUT_DATA, b);
|
||||
}
|
||||
#ifdef CONFIG_VIDEO_HW_CURSOR
|
||||
/*-----------------------------------------------------------------------------
|
||||
* video_set_hw_cursor --
|
||||
*-----------------------------------------------------------------------------
|
||||
*/
|
||||
void video_set_hw_cursor (int x, int y)
|
||||
{
|
||||
writeByte (LCD_CURSOR_XL, (x & 0xff));
|
||||
writeByte (LCD_CURSOR_XM, (x >> 8));
|
||||
writeByte (LCD_CURSOR_YL, (y & 0xff));
|
||||
writeByte (LCD_CURSOR_YM, (y >> 8));
|
||||
}
|
||||
|
||||
/*-----------------------------------------------------------------------------
|
||||
* video_init_hw_cursor --
|
||||
*-----------------------------------------------------------------------------
|
||||
*/
|
||||
void video_init_hw_cursor (int font_width, int font_height)
|
||||
{
|
||||
volatile unsigned char *ptr;
|
||||
unsigned char pattern;
|
||||
int i;
|
||||
|
||||
|
||||
/* Init cursor content
|
||||
Cursor size is 64x64 pixels
|
||||
Start of the cursor memory depends on panel type (dual panel ...) */
|
||||
if ((i = readByte (LCD_CURSOR_START)) == 0) {
|
||||
ptr = (unsigned char *)(sed13806.frameAdrs + DEFAULT_VIDEO_MEMORY_SIZE - HWCURSORSIZE);
|
||||
}
|
||||
else {
|
||||
ptr = (unsigned char *)(sed13806.frameAdrs + DEFAULT_VIDEO_MEMORY_SIZE - (i * 8192));
|
||||
}
|
||||
|
||||
/* Fill the first line and the first empty line after cursor */
|
||||
for (i = 0, pattern = 0; i < 64; i++) {
|
||||
if (i < font_width) {
|
||||
/* Invert background */
|
||||
pattern |= 0x3;
|
||||
|
||||
}
|
||||
else {
|
||||
/* Background */
|
||||
pattern |= 0x2;
|
||||
}
|
||||
if ((i & 3) == 3) {
|
||||
*ptr = pattern;
|
||||
*(ptr + font_height * 16) = 0xaa;
|
||||
ptr ++;
|
||||
pattern = 0;
|
||||
}
|
||||
pattern <<= 2;
|
||||
}
|
||||
|
||||
/* Duplicate this line */
|
||||
for (i = 1; i < font_height; i++) {
|
||||
memcpy ((void *)ptr, (void *)(ptr - 16), 16);
|
||||
ptr += 16;
|
||||
}
|
||||
|
||||
for (; i < 64; i++) {
|
||||
memcpy ((void *)(ptr + 16), (void *)ptr, 16);
|
||||
ptr += 16;
|
||||
}
|
||||
|
||||
/* Select cursor mode */
|
||||
writeByte (LCD_CURSOR_CNTL, 1);
|
||||
}
|
||||
#endif
|
||||
563
common/package/boot/uboot-ipq40xx/src/drivers/video/sed156x.c
Normal file
563
common/package/boot/uboot-ipq40xx/src/drivers/video/sed156x.c
Normal file
|
|
@ -0,0 +1,563 @@
|
|||
/*
|
||||
* (C) Copyright 2003
|
||||
*
|
||||
* Pantelis Antoniou <panto@intracom.gr>
|
||||
* Intracom S.A.
|
||||
*
|
||||
* See file CREDITS for list of people who contributed to this
|
||||
* project.
|
||||
*
|
||||
* 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 <common.h>
|
||||
#include <watchdog.h>
|
||||
|
||||
#include <sed156x.h>
|
||||
|
||||
/* configure according to the selected display */
|
||||
#if defined(CONFIG_SED156X_PG12864Q)
|
||||
#define LCD_WIDTH 128
|
||||
#define LCD_HEIGHT 64
|
||||
#define LCD_LINES 64
|
||||
#define LCD_PAGES 9
|
||||
#define LCD_COLUMNS 132
|
||||
#else
|
||||
#error Unsupported SED156x configuration
|
||||
#endif
|
||||
|
||||
/* include the font data */
|
||||
#include <video_font.h>
|
||||
#include <video_font_data.h>
|
||||
|
||||
#if VIDEO_FONT_WIDTH != 8 || VIDEO_FONT_HEIGHT != 16
|
||||
#error Expecting VIDEO_FONT_WIDTH == 8 && VIDEO_FONT_HEIGHT == 16
|
||||
#endif
|
||||
|
||||
#define LCD_BYTE_WIDTH (LCD_WIDTH / 8)
|
||||
#define VIDEO_FONT_BYTE_WIDTH (VIDEO_FONT_WIDTH / 8)
|
||||
|
||||
#define LCD_TEXT_WIDTH (LCD_WIDTH / VIDEO_FONT_WIDTH)
|
||||
#define LCD_TEXT_HEIGHT (LCD_HEIGHT / VIDEO_FONT_HEIGHT)
|
||||
|
||||
#define LCD_BYTE_LINESZ (LCD_BYTE_WIDTH * VIDEO_FONT_HEIGHT)
|
||||
|
||||
const int sed156x_text_width = LCD_TEXT_WIDTH;
|
||||
const int sed156x_text_height = LCD_TEXT_HEIGHT;
|
||||
|
||||
/**************************************************************************************/
|
||||
|
||||
#define SED156X_SPI_RXD() (SED156X_SPI_RXD_PORT & SED156X_SPI_RXD_MASK)
|
||||
|
||||
#define SED156X_SPI_TXD(x) \
|
||||
do { \
|
||||
if (x) \
|
||||
SED156X_SPI_TXD_PORT |= SED156X_SPI_TXD_MASK; \
|
||||
else \
|
||||
SED156X_SPI_TXD_PORT &= ~SED156X_SPI_TXD_MASK; \
|
||||
} while(0)
|
||||
|
||||
#define SED156X_SPI_CLK(x) \
|
||||
do { \
|
||||
if (x) \
|
||||
SED156X_SPI_CLK_PORT |= SED156X_SPI_CLK_MASK; \
|
||||
else \
|
||||
SED156X_SPI_CLK_PORT &= ~SED156X_SPI_CLK_MASK; \
|
||||
} while(0)
|
||||
|
||||
#define SED156X_SPI_CLK_TOGGLE() (SED156X_SPI_CLK_PORT ^= SED156X_SPI_CLK_MASK)
|
||||
|
||||
#define SED156X_SPI_BIT_DELAY() /* no delay */
|
||||
|
||||
#define SED156X_CS(x) \
|
||||
do { \
|
||||
if (x) \
|
||||
SED156X_CS_PORT |= SED156X_CS_MASK; \
|
||||
else \
|
||||
SED156X_CS_PORT &= ~SED156X_CS_MASK; \
|
||||
} while(0)
|
||||
|
||||
#define SED156X_A0(x) \
|
||||
do { \
|
||||
if (x) \
|
||||
SED156X_A0_PORT |= SED156X_A0_MASK; \
|
||||
else \
|
||||
SED156X_A0_PORT &= ~SED156X_A0_MASK; \
|
||||
} while(0)
|
||||
|
||||
/**************************************************************************************/
|
||||
|
||||
/*** LCD Commands ***/
|
||||
|
||||
#define LCD_ON 0xAF /* Display ON */
|
||||
#define LCD_OFF 0xAE /* Display OFF */
|
||||
#define LCD_LADDR 0x40 /* Display start line set + (6-bit) address */
|
||||
#define LCD_PADDR 0xB0 /* Page address set + (4-bit) page */
|
||||
#define LCD_CADRH 0x10 /* Column address set upper + (4-bit) column hi */
|
||||
#define LCD_CADRL 0x00 /* Column address set lower + (4-bit) column lo */
|
||||
#define LCD_ADC_NRM 0xA0 /* ADC select Normal */
|
||||
#define LCD_ADC_REV 0xA1 /* ADC select Reverse */
|
||||
#define LCD_DSP_NRM 0xA6 /* LCD display Normal */
|
||||
#define LCD_DSP_REV 0xA7 /* LCD display Reverse */
|
||||
#define LCD_DPT_NRM 0xA4 /* Display all points Normal */
|
||||
#define LCD_DPT_ALL 0xA5 /* Display all points ON */
|
||||
#define LCD_BIAS9 0xA2 /* LCD bias set 1/9 */
|
||||
#define LCD_BIAS7 0xA3 /* LCD bias set 1/7 */
|
||||
#define LCD_CAINC 0xE0 /* Read/modify/write */
|
||||
#define LCD_CAEND 0xEE /* End */
|
||||
#define LCD_RESET 0xE2 /* Reset */
|
||||
#define LCD_C_NRM 0xC0 /* Common output mode select Normal direction */
|
||||
#define LCD_C_RVS 0xC8 /* Common output mode select Reverse direction */
|
||||
#define LCD_PWRMD 0x28 /* Power control set + (3-bit) mode */
|
||||
#define LCD_RESRT 0x20 /* V5 v. reg. int. resistor ratio set + (3-bit) ratio */
|
||||
#define LCD_EVSET 0x81 /* Electronic volume mode set + byte = (6-bit) volume */
|
||||
#define LCD_SIOFF 0xAC /* Static indicator OFF */
|
||||
#define LCD_SION 0xAD /* Static indicator ON + byte = (2-bit) mode */
|
||||
#define LCD_NOP 0xE3 /* NOP */
|
||||
#define LCD_TEST 0xF0 /* Test/Test mode reset (Note: *DO NOT USE*) */
|
||||
|
||||
/*-------------------------------------------------------------------------------
|
||||
Compound commands
|
||||
-------------------------------------------------------------------------------
|
||||
Command Description Commands
|
||||
---------- ------------------------ -------------------------------------
|
||||
POWS_ON POWER SAVER ON command LCD_OFF, LCD_D_ALL
|
||||
POWS_OFF POWER SAVER OFF command LCD_D_NRM
|
||||
SLEEPON SLEEP mode LCD_SIOFF, POWS_ON
|
||||
SLEEPOFF SLEEP mode cancel LCD_D_NRM, LCD_SION, LCD_SIS_???
|
||||
STDBYON STAND BY mode LCD_SION, POWS_ON
|
||||
STDBYOFF STAND BY mode cancel LCD_D_NRM
|
||||
-------------------------------------------------------------------------------*/
|
||||
|
||||
/*** LCD various parameters ***/
|
||||
#define LCD_PPB 8 /* Pixels per byte (display is B/W, 1 bit per pixel) */
|
||||
|
||||
/*** LCD Status byte masks ***/
|
||||
#define LCD_S_BUSY 0x80 /* Status Read - BUSY mask */
|
||||
#define LCD_S_ADC 0x40 /* Status Read - ADC mask */
|
||||
#define LCD_S_ONOFF 0x20 /* Status Read - ON/OFF mask */
|
||||
#define LCD_S_RESET 0x10 /* Status Read - RESET mask */
|
||||
|
||||
/*** LCD commands parameter masks ***/
|
||||
#define LCD_M_LADDR 0x3F /* Display start line (6-bit) address mask */
|
||||
#define LCD_M_PADDR 0x0F /* Page address (4-bit) page mask */
|
||||
#define LCD_M_CADRH 0x0F /* Column address upper (4-bit) column hi mask */
|
||||
#define LCD_M_CADRL 0x0F /* Column address lower (4-bit) column lo mask */
|
||||
#define LCD_M_PWRMD 0x07 /* Power control (3-bit) mode mask */
|
||||
#define LCD_M_RESRT 0x07 /* V5 v. reg. int. resistor ratio (3-bit) ratio mask */
|
||||
#define LCD_M_EVSET 0x3F /* Electronic volume mode byte (6-bit) volume mask */
|
||||
#define LCD_M_SION 0x03 /* Static indicator ON (2-bit) mode mask */
|
||||
|
||||
/*** LCD Power control cirquits control masks ***/
|
||||
#define LCD_PWRBSTR 0x04 /* Power control mode - Booster cirquit ON */
|
||||
#define LCD_PWRVREG 0x02 /* Power control mode - Voltage regulator cirquit ON */
|
||||
#define LCD_PWRVFOL 0x01 /* Power control mode - Voltage follower cirquit ON */
|
||||
|
||||
/*** LCD Static indicator states ***/
|
||||
#define LCD_SIS_OFF 0x00 /* Static indicator register set - OFF state */
|
||||
#define LCD_SIS_BL 0x01 /* Static indicator register set - 1s blink state */
|
||||
#define LCD_SIS_RBL 0x02 /* Static indicator register set - .5s rapid blink state */
|
||||
#define LCD_SIS_ON 0x03 /* Static indicator register set - constantly on state */
|
||||
|
||||
/*** LCD functions special parameters (commands) ***/
|
||||
#define LCD_PREVP 0x80 /* Page number for moving to previous */
|
||||
#define LCD_NEXTP 0x81 /* or next page */
|
||||
#define LCD_ERR_P 0xFF /* Error in page number */
|
||||
|
||||
/*** LCD initialization settings ***/
|
||||
#define LCD_BIAS LCD_BIAS9 /* Bias: 1/9 */
|
||||
#define LCD_ADCMODE LCD_ADC_NRM /* ADC mode: normal */
|
||||
#define LCD_COMDIR LCD_C_NRM /* Common output mode: normal */
|
||||
#define LCD_RRATIO 0 /* Resistor ratio: 0 */
|
||||
#define LCD_CNTRST 0x1C /* electronic volume: 1Ch */
|
||||
#define LCD_POWERM (LCD_PWRBSTR | LCD_PWRVREG | LCD_PWRVFOL) /* Power mode: All on */
|
||||
|
||||
/**************************************************************************************/
|
||||
|
||||
static inline unsigned int sed156x_transfer(unsigned int val)
|
||||
{
|
||||
unsigned int rx;
|
||||
int b;
|
||||
|
||||
rx = 0; b = 8;
|
||||
while (--b >= 0) {
|
||||
SED156X_SPI_TXD(val & 0x80);
|
||||
val <<= 1;
|
||||
SED156X_SPI_CLK_TOGGLE();
|
||||
SED156X_SPI_BIT_DELAY();
|
||||
rx <<= 1;
|
||||
if (SED156X_SPI_RXD())
|
||||
rx |= 1;
|
||||
SED156X_SPI_CLK_TOGGLE();
|
||||
SED156X_SPI_BIT_DELAY();
|
||||
}
|
||||
|
||||
return rx;
|
||||
}
|
||||
|
||||
unsigned int sed156x_data_transfer(unsigned int val)
|
||||
{
|
||||
unsigned int rx;
|
||||
|
||||
SED156X_SPI_CLK(1);
|
||||
SED156X_CS(0);
|
||||
SED156X_A0(1);
|
||||
|
||||
rx = sed156x_transfer(val);
|
||||
|
||||
SED156X_CS(1);
|
||||
|
||||
return rx;
|
||||
}
|
||||
|
||||
void sed156x_data_block_transfer(const u8 *p, int size)
|
||||
{
|
||||
SED156X_SPI_CLK(1);
|
||||
SED156X_CS(0);
|
||||
SED156X_A0(1);
|
||||
|
||||
while (--size >= 0)
|
||||
sed156x_transfer(*p++);
|
||||
|
||||
SED156X_CS(1);
|
||||
}
|
||||
|
||||
unsigned int sed156x_cmd_transfer(unsigned int val)
|
||||
{
|
||||
unsigned int rx;
|
||||
|
||||
SED156X_SPI_CLK(1);
|
||||
SED156X_CS(0);
|
||||
SED156X_A0(0);
|
||||
|
||||
rx = sed156x_transfer(val);
|
||||
|
||||
SED156X_CS(1);
|
||||
SED156X_A0(1);
|
||||
|
||||
return rx;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
static u8 hw_screen[LCD_PAGES][LCD_COLUMNS];
|
||||
static u8 last_hw_screen[LCD_PAGES][LCD_COLUMNS];
|
||||
static u8 sw_screen[LCD_BYTE_WIDTH * LCD_HEIGHT];
|
||||
|
||||
void sed156x_sync(void)
|
||||
{
|
||||
int i, j, last_page;
|
||||
u8 *d;
|
||||
const u8 *s, *e, *b, *r;
|
||||
u8 v0, v1, v2, v3, v4, v5, v6, v7;
|
||||
|
||||
/* copy and rotate sw_screen to hw_screen */
|
||||
for (i = 0; i < LCD_HEIGHT / 8; i++) {
|
||||
|
||||
d = &hw_screen[i][0];
|
||||
s = &sw_screen[LCD_BYTE_WIDTH * 8 * i + LCD_BYTE_WIDTH - 1];
|
||||
|
||||
for (j = 0; j < LCD_WIDTH / 8; j++) {
|
||||
|
||||
v0 = s[0 * LCD_BYTE_WIDTH];
|
||||
v1 = s[1 * LCD_BYTE_WIDTH];
|
||||
v2 = s[2 * LCD_BYTE_WIDTH];
|
||||
v3 = s[3 * LCD_BYTE_WIDTH];
|
||||
v4 = s[4 * LCD_BYTE_WIDTH];
|
||||
v5 = s[5 * LCD_BYTE_WIDTH];
|
||||
v6 = s[6 * LCD_BYTE_WIDTH];
|
||||
v7 = s[7 * LCD_BYTE_WIDTH];
|
||||
|
||||
d[0] = ((v7 & 0x01) << 7) |
|
||||
((v6 & 0x01) << 6) |
|
||||
((v5 & 0x01) << 5) |
|
||||
((v4 & 0x01) << 4) |
|
||||
((v3 & 0x01) << 3) |
|
||||
((v2 & 0x01) << 2) |
|
||||
((v1 & 0x01) << 1) |
|
||||
(v0 & 0x01) ;
|
||||
|
||||
d[1] = ((v7 & 0x02) << 6) |
|
||||
((v6 & 0x02) << 5) |
|
||||
((v5 & 0x02) << 4) |
|
||||
((v4 & 0x02) << 3) |
|
||||
((v3 & 0x02) << 2) |
|
||||
((v2 & 0x02) << 1) |
|
||||
((v1 & 0x02) << 0) |
|
||||
((v0 & 0x02) >> 1) ;
|
||||
|
||||
d[2] = ((v7 & 0x04) << 5) |
|
||||
((v6 & 0x04) << 4) |
|
||||
((v5 & 0x04) << 3) |
|
||||
((v4 & 0x04) << 2) |
|
||||
((v3 & 0x04) << 1) |
|
||||
(v2 & 0x04) |
|
||||
((v1 & 0x04) >> 1) |
|
||||
((v0 & 0x04) >> 2) ;
|
||||
|
||||
d[3] = ((v7 & 0x08) << 4) |
|
||||
((v6 & 0x08) << 3) |
|
||||
((v5 & 0x08) << 2) |
|
||||
((v4 & 0x08) << 1) |
|
||||
(v3 & 0x08) |
|
||||
((v2 & 0x08) >> 1) |
|
||||
((v1 & 0x08) >> 2) |
|
||||
((v0 & 0x08) >> 3) ;
|
||||
|
||||
d[4] = ((v7 & 0x10) << 3) |
|
||||
((v6 & 0x10) << 2) |
|
||||
((v5 & 0x10) << 1) |
|
||||
(v4 & 0x10) |
|
||||
((v3 & 0x10) >> 1) |
|
||||
((v2 & 0x10) >> 2) |
|
||||
((v1 & 0x10) >> 3) |
|
||||
((v0 & 0x10) >> 4) ;
|
||||
|
||||
d[5] = ((v7 & 0x20) << 2) |
|
||||
((v6 & 0x20) << 1) |
|
||||
(v5 & 0x20) |
|
||||
((v4 & 0x20) >> 1) |
|
||||
((v3 & 0x20) >> 2) |
|
||||
((v2 & 0x20) >> 3) |
|
||||
((v1 & 0x20) >> 4) |
|
||||
((v0 & 0x20) >> 5) ;
|
||||
|
||||
d[6] = ((v7 & 0x40) << 1) |
|
||||
(v6 & 0x40) |
|
||||
((v5 & 0x40) >> 1) |
|
||||
((v4 & 0x40) >> 2) |
|
||||
((v3 & 0x40) >> 3) |
|
||||
((v2 & 0x40) >> 4) |
|
||||
((v1 & 0x40) >> 5) |
|
||||
((v0 & 0x40) >> 6) ;
|
||||
|
||||
d[7] = (v7 & 0x80) |
|
||||
((v6 & 0x80) >> 1) |
|
||||
((v5 & 0x80) >> 2) |
|
||||
((v4 & 0x80) >> 3) |
|
||||
((v3 & 0x80) >> 4) |
|
||||
((v2 & 0x80) >> 5) |
|
||||
((v1 & 0x80) >> 6) |
|
||||
((v0 & 0x80) >> 7) ;
|
||||
|
||||
d += 8;
|
||||
s--;
|
||||
}
|
||||
}
|
||||
|
||||
/* and now output only the differences */
|
||||
for (i = 0; i < LCD_PAGES; i++) {
|
||||
|
||||
b = &hw_screen[i][0];
|
||||
e = &hw_screen[i][LCD_COLUMNS];
|
||||
|
||||
d = &last_hw_screen[i][0];
|
||||
s = b;
|
||||
|
||||
last_page = -1;
|
||||
|
||||
/* update only the differences */
|
||||
do {
|
||||
while (s < e && *s == *d) {
|
||||
s++;
|
||||
d++;
|
||||
}
|
||||
if (s == e)
|
||||
break;
|
||||
r = s;
|
||||
while (s < e && *s != *d)
|
||||
*d++ = *s++;
|
||||
|
||||
j = r - b;
|
||||
|
||||
if (i != last_page) {
|
||||
sed156x_cmd_transfer(LCD_PADDR | i);
|
||||
last_page = i;
|
||||
}
|
||||
|
||||
sed156x_cmd_transfer(LCD_CADRH | ((j >> 4) & 0x0F));
|
||||
sed156x_cmd_transfer(LCD_CADRL | (j & 0x0F));
|
||||
sed156x_data_block_transfer(r, s - r);
|
||||
|
||||
} while (s < e);
|
||||
}
|
||||
|
||||
/********
|
||||
for (i = 0; i < LCD_PAGES; i++) {
|
||||
sed156x_cmd_transfer(LCD_PADDR | i);
|
||||
sed156x_cmd_transfer(LCD_CADRH | 0);
|
||||
sed156x_cmd_transfer(LCD_CADRL | 0);
|
||||
sed156x_data_block_transfer(&hw_screen[i][0], LCD_COLUMNS);
|
||||
}
|
||||
memcpy(last_hw_screen, hw_screen, sizeof(last_hw_screen));
|
||||
********/
|
||||
}
|
||||
|
||||
void sed156x_clear(void)
|
||||
{
|
||||
memset(sw_screen, 0, sizeof(sw_screen));
|
||||
}
|
||||
|
||||
void sed156x_output_at(int x, int y, const char *str, int size)
|
||||
{
|
||||
int i, j;
|
||||
u8 *p;
|
||||
const u8 *s;
|
||||
|
||||
if ((unsigned int)y >= LCD_TEXT_HEIGHT || (unsigned int)x >= LCD_TEXT_WIDTH)
|
||||
return;
|
||||
|
||||
p = &sw_screen[y * VIDEO_FONT_HEIGHT * LCD_BYTE_WIDTH + x * VIDEO_FONT_BYTE_WIDTH];
|
||||
|
||||
while (--size >= 0) {
|
||||
|
||||
s = &video_fontdata[((int)*str++ & 0xff) * VIDEO_FONT_BYTE_WIDTH * VIDEO_FONT_HEIGHT];
|
||||
for (i = 0; i < VIDEO_FONT_HEIGHT; i++) {
|
||||
for (j = 0; j < VIDEO_FONT_BYTE_WIDTH; j++)
|
||||
*p++ = *s++;
|
||||
p += LCD_BYTE_WIDTH - VIDEO_FONT_BYTE_WIDTH;
|
||||
}
|
||||
p -= (LCD_BYTE_LINESZ - VIDEO_FONT_BYTE_WIDTH);
|
||||
|
||||
if (x >= LCD_TEXT_WIDTH)
|
||||
break;
|
||||
x++;
|
||||
}
|
||||
}
|
||||
|
||||
void sed156x_reverse_at(int x, int y, int size)
|
||||
{
|
||||
int i, j;
|
||||
u8 *p;
|
||||
|
||||
if ((unsigned int)y >= LCD_TEXT_HEIGHT || (unsigned int)x >= LCD_TEXT_WIDTH)
|
||||
return;
|
||||
|
||||
p = &sw_screen[y * VIDEO_FONT_HEIGHT * LCD_BYTE_WIDTH + x * VIDEO_FONT_BYTE_WIDTH];
|
||||
|
||||
while (--size >= 0) {
|
||||
|
||||
for (i = 0; i < VIDEO_FONT_HEIGHT; i++) {
|
||||
for (j = 0; j < VIDEO_FONT_BYTE_WIDTH; j++, p++)
|
||||
*p = ~*p;
|
||||
p += LCD_BYTE_WIDTH - VIDEO_FONT_BYTE_WIDTH;
|
||||
}
|
||||
p -= (LCD_BYTE_LINESZ - VIDEO_FONT_BYTE_WIDTH);
|
||||
|
||||
if (x >= LCD_TEXT_WIDTH)
|
||||
break;
|
||||
x++;
|
||||
}
|
||||
}
|
||||
|
||||
void sed156x_scroll_line(void)
|
||||
{
|
||||
memmove(&sw_screen[0],
|
||||
&sw_screen[LCD_BYTE_LINESZ],
|
||||
LCD_BYTE_WIDTH * (LCD_HEIGHT - VIDEO_FONT_HEIGHT));
|
||||
}
|
||||
|
||||
void sed156x_scroll(int dx, int dy)
|
||||
{
|
||||
u8 *p1 = NULL, *p2 = NULL, *p3 = NULL; /* pacify gcc */
|
||||
int adx, ady, i, sz;
|
||||
|
||||
adx = dx > 0 ? dx : -dx;
|
||||
ady = dy > 0 ? dy : -dy;
|
||||
|
||||
/* overscroll? erase everything */
|
||||
if (adx >= LCD_TEXT_WIDTH || ady >= LCD_TEXT_HEIGHT) {
|
||||
memset(sw_screen, 0, sizeof(sw_screen));
|
||||
return;
|
||||
}
|
||||
|
||||
sz = LCD_BYTE_LINESZ * ady;
|
||||
if (dy > 0) {
|
||||
p1 = &sw_screen[0];
|
||||
p2 = &sw_screen[sz];
|
||||
p3 = &sw_screen[LCD_BYTE_WIDTH * LCD_HEIGHT - sz];
|
||||
} else if (dy < 0) {
|
||||
p1 = &sw_screen[sz];
|
||||
p2 = &sw_screen[0];
|
||||
p3 = &sw_screen[0];
|
||||
}
|
||||
|
||||
if (ady > 0) {
|
||||
memmove(p1, p2, LCD_BYTE_WIDTH * LCD_HEIGHT - sz);
|
||||
memset(p3, 0, sz);
|
||||
}
|
||||
|
||||
sz = VIDEO_FONT_BYTE_WIDTH * adx;
|
||||
if (dx > 0) {
|
||||
p1 = &sw_screen[0];
|
||||
p2 = &sw_screen[0] + sz;
|
||||
p3 = &sw_screen[0] + LCD_BYTE_WIDTH - sz;
|
||||
} else if (dx < 0) {
|
||||
p1 = &sw_screen[0] + sz;
|
||||
p2 = &sw_screen[0];
|
||||
p3 = &sw_screen[0];
|
||||
}
|
||||
|
||||
/* xscroll */
|
||||
if (adx > 0) {
|
||||
for (i = 0; i < LCD_HEIGHT; i++) {
|
||||
memmove(p1, p2, LCD_BYTE_WIDTH - sz);
|
||||
memset(p3, 0, sz);
|
||||
p1 += LCD_BYTE_WIDTH;
|
||||
p2 += LCD_BYTE_WIDTH;
|
||||
p3 += LCD_BYTE_WIDTH;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void sed156x_init(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
SED156X_CS(1);
|
||||
SED156X_A0(1);
|
||||
|
||||
/* Send initialization commands to the LCD */
|
||||
sed156x_cmd_transfer(LCD_OFF); /* Turn display OFF */
|
||||
sed156x_cmd_transfer(LCD_BIAS); /* set the LCD Bias, */
|
||||
sed156x_cmd_transfer(LCD_ADCMODE); /* ADC mode, */
|
||||
sed156x_cmd_transfer(LCD_COMDIR); /* common output mode, */
|
||||
sed156x_cmd_transfer(LCD_RESRT | LCD_RRATIO); /* resistor ratio, */
|
||||
sed156x_cmd_transfer(LCD_EVSET); /* electronic volume, */
|
||||
sed156x_cmd_transfer(LCD_CNTRST);
|
||||
sed156x_cmd_transfer(LCD_PWRMD | LCD_POWERM); /* and power mode */
|
||||
sed156x_cmd_transfer(LCD_PADDR | 0); /* cursor home */
|
||||
sed156x_cmd_transfer(LCD_CADRH | 0);
|
||||
sed156x_cmd_transfer(LCD_CADRL | 0);
|
||||
sed156x_cmd_transfer(LCD_LADDR | 0); /* and display start line */
|
||||
sed156x_cmd_transfer(LCD_DSP_NRM); /* LCD display Normal */
|
||||
|
||||
/* clear everything */
|
||||
memset(sw_screen, 0, sizeof(sw_screen));
|
||||
memset(hw_screen, 0, sizeof(hw_screen));
|
||||
memset(last_hw_screen, 0, sizeof(last_hw_screen));
|
||||
|
||||
for (i = 0; i < LCD_PAGES; i++) {
|
||||
sed156x_cmd_transfer(LCD_PADDR | i);
|
||||
sed156x_cmd_transfer(LCD_CADRH | 0);
|
||||
sed156x_cmd_transfer(LCD_CADRL | 0);
|
||||
sed156x_data_block_transfer(&hw_screen[i][0], LCD_COLUMNS);
|
||||
}
|
||||
|
||||
sed156x_clear();
|
||||
sed156x_sync();
|
||||
sed156x_cmd_transfer(LCD_ON); /* Turn display ON */
|
||||
}
|
||||
240
common/package/boot/uboot-ipq40xx/src/drivers/video/sm501.c
Normal file
240
common/package/boot/uboot-ipq40xx/src/drivers/video/sm501.c
Normal file
|
|
@ -0,0 +1,240 @@
|
|||
/*
|
||||
* (C) Copyright 2002
|
||||
* Stäubli Faverges - <www.staubli.com>
|
||||
* Pierre AUBERT p.aubert@staubli.com
|
||||
*
|
||||
* (C) Copyright 2005
|
||||
* Martin Krause TQ-Systems GmbH martin.krause@tqs.de
|
||||
*
|
||||
* See file CREDITS for list of people who contributed to this
|
||||
* project.
|
||||
*
|
||||
* 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
|
||||
*/
|
||||
|
||||
/*
|
||||
* Basic video support for SMI SM501 "Voyager" graphic controller
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
|
||||
#include <asm/io.h>
|
||||
#include <video_fb.h>
|
||||
#include <sm501.h>
|
||||
|
||||
#define read8(ptrReg) \
|
||||
*(volatile unsigned char *)(sm501.isaBase + ptrReg)
|
||||
|
||||
#define write8(ptrReg,value) \
|
||||
*(volatile unsigned char *)(sm501.isaBase + ptrReg) = value
|
||||
|
||||
#define read16(ptrReg) \
|
||||
(*(volatile unsigned short *)(sm501.isaBase + ptrReg))
|
||||
|
||||
#define write16(ptrReg,value) \
|
||||
(*(volatile unsigned short *)(sm501.isaBase + ptrReg) = value)
|
||||
|
||||
#define read32(ptrReg) \
|
||||
(*(volatile unsigned int *)(sm501.isaBase + ptrReg))
|
||||
|
||||
#define write32(ptrReg, value) \
|
||||
(*(volatile unsigned int *)(sm501.isaBase + ptrReg) = value)
|
||||
|
||||
GraphicDevice sm501;
|
||||
|
||||
void write_be32(int off, unsigned int val)
|
||||
{
|
||||
out_be32((unsigned __iomem *)(sm501.isaBase + off), val);
|
||||
}
|
||||
|
||||
void write_le32(int off, unsigned int val)
|
||||
{
|
||||
out_le32((unsigned __iomem *)(sm501.isaBase + off), val);
|
||||
}
|
||||
|
||||
void (*write_reg32)(int off, unsigned int val) = write_be32;
|
||||
|
||||
/*-----------------------------------------------------------------------------
|
||||
* SmiSetRegs --
|
||||
*-----------------------------------------------------------------------------
|
||||
*/
|
||||
static void SmiSetRegs (void)
|
||||
{
|
||||
/*
|
||||
* The content of the chipset register depends on the board (clocks,
|
||||
* ...)
|
||||
*/
|
||||
const SMI_REGS *preg = board_get_regs ();
|
||||
while (preg->Index) {
|
||||
write_reg32 (preg->Index, preg->Value);
|
||||
/*
|
||||
* Insert a delay between
|
||||
*/
|
||||
udelay (1000);
|
||||
preg ++;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef CONFIG_VIDEO_SM501_PCI
|
||||
static struct pci_device_id sm501_pci_tbl[] = {
|
||||
{ PCI_VENDOR_ID_SMI, PCI_DEVICE_ID_SMI_501 },
|
||||
{}
|
||||
};
|
||||
#endif
|
||||
|
||||
/*
|
||||
* We do not enforce board code to provide empty/unused
|
||||
* functions for this driver and define weak default
|
||||
* functions here.
|
||||
*/
|
||||
unsigned int __board_video_init (void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
unsigned int board_video_init (void)
|
||||
__attribute__((weak, alias("__board_video_init")));
|
||||
|
||||
unsigned int __board_video_get_fb (void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
unsigned int board_video_get_fb (void)
|
||||
__attribute__((weak, alias("__board_video_get_fb")));
|
||||
|
||||
void __board_validate_screen (unsigned int base)
|
||||
{
|
||||
}
|
||||
|
||||
void board_validate_screen (unsigned int base)
|
||||
__attribute__((weak, alias("__board_validate_screen")));
|
||||
|
||||
/*-----------------------------------------------------------------------------
|
||||
* video_hw_init --
|
||||
*-----------------------------------------------------------------------------
|
||||
*/
|
||||
void *video_hw_init (void)
|
||||
{
|
||||
#ifdef CONFIG_VIDEO_SM501_PCI
|
||||
unsigned int pci_mem_base, pci_mmio_base;
|
||||
unsigned int id;
|
||||
unsigned short device_id;
|
||||
pci_dev_t devbusfn;
|
||||
int mem;
|
||||
#endif
|
||||
unsigned int *vm, i;
|
||||
|
||||
memset (&sm501, 0, sizeof (GraphicDevice));
|
||||
|
||||
#ifdef CONFIG_VIDEO_SM501_PCI
|
||||
printf("Video: ");
|
||||
|
||||
/* Look for SM501/SM502 chips */
|
||||
devbusfn = pci_find_devices(sm501_pci_tbl, 0);
|
||||
if (devbusfn < 0) {
|
||||
printf ("PCI Controller not found.\n");
|
||||
goto not_pci;
|
||||
}
|
||||
|
||||
/* Setup */
|
||||
pci_write_config_dword (devbusfn, PCI_COMMAND,
|
||||
(PCI_COMMAND_MEMORY | PCI_COMMAND_IO));
|
||||
pci_read_config_word (devbusfn, PCI_DEVICE_ID, &device_id);
|
||||
pci_read_config_dword (devbusfn, PCI_REVISION_ID, &id);
|
||||
pci_read_config_dword (devbusfn, PCI_BASE_ADDRESS_0, &pci_mem_base);
|
||||
pci_read_config_dword (devbusfn, PCI_BASE_ADDRESS_1, &pci_mmio_base);
|
||||
sm501.frameAdrs = pci_mem_to_phys (devbusfn, pci_mem_base);
|
||||
sm501.isaBase = pci_mem_to_phys (devbusfn, pci_mmio_base);
|
||||
|
||||
if (sm501.isaBase)
|
||||
write_reg32 = write_le32;
|
||||
|
||||
mem = in_le32 ((unsigned __iomem *)(sm501.isaBase + 0x10));
|
||||
mem = (mem & 0x0000e000) >> 13;
|
||||
switch (mem) {
|
||||
case 1:
|
||||
mem = 8;
|
||||
break;
|
||||
case 2:
|
||||
mem = 16;
|
||||
break;
|
||||
case 3:
|
||||
mem = 32;
|
||||
break;
|
||||
case 4:
|
||||
mem = 64;
|
||||
break;
|
||||
case 5:
|
||||
mem = 2;
|
||||
break;
|
||||
case 0:
|
||||
default:
|
||||
mem = 4;
|
||||
}
|
||||
printf ("PCI SM50%d %d MB\n", ((id & 0xff) == 0xC0) ? 2 : 1, mem);
|
||||
not_pci:
|
||||
#endif
|
||||
/*
|
||||
* Initialization of the access to the graphic chipset Retreive base
|
||||
* address of the chipset (see board/RPXClassic/eccx.c)
|
||||
*/
|
||||
if (!sm501.isaBase) {
|
||||
sm501.isaBase = board_video_init ();
|
||||
if (!sm501.isaBase)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!sm501.frameAdrs) {
|
||||
sm501.frameAdrs = board_video_get_fb ();
|
||||
if (!sm501.frameAdrs)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
sm501.winSizeX = board_get_width ();
|
||||
sm501.winSizeY = board_get_height ();
|
||||
|
||||
#if defined(CONFIG_VIDEO_SM501_8BPP)
|
||||
sm501.gdfIndex = GDF__8BIT_INDEX;
|
||||
sm501.gdfBytesPP = 1;
|
||||
|
||||
#elif defined(CONFIG_VIDEO_SM501_16BPP)
|
||||
sm501.gdfIndex = GDF_16BIT_565RGB;
|
||||
sm501.gdfBytesPP = 2;
|
||||
|
||||
#elif defined(CONFIG_VIDEO_SM501_32BPP)
|
||||
sm501.gdfIndex = GDF_32BIT_X888RGB;
|
||||
sm501.gdfBytesPP = 4;
|
||||
#else
|
||||
#error Unsupported SM501 BPP
|
||||
#endif
|
||||
|
||||
sm501.memSize = sm501.winSizeX * sm501.winSizeY * sm501.gdfBytesPP;
|
||||
|
||||
/* Load Smi registers */
|
||||
SmiSetRegs ();
|
||||
|
||||
/* (see board/RPXClassic/RPXClassic.c) */
|
||||
board_validate_screen (sm501.isaBase);
|
||||
|
||||
/* Clear video memory */
|
||||
i = sm501.memSize/4;
|
||||
vm = (unsigned int *)sm501.frameAdrs;
|
||||
while(i--)
|
||||
*vm++ = 0;
|
||||
|
||||
return (&sm501);
|
||||
}
|
||||
854
common/package/boot/uboot-ipq40xx/src/drivers/video/smiLynxEM.c
Normal file
854
common/package/boot/uboot-ipq40xx/src/drivers/video/smiLynxEM.c
Normal file
|
|
@ -0,0 +1,854 @@
|
|||
/*
|
||||
* (C) Copyright 1997-2002 ELTEC Elektronik AG
|
||||
* Frank Gottschling <fgottschling@eltec.de>
|
||||
*
|
||||
* See file CREDITS for list of people who contributed to this
|
||||
* project.
|
||||
*
|
||||
* 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
|
||||
*/
|
||||
|
||||
/*
|
||||
* smiLynxEM.c
|
||||
*
|
||||
* Silicon Motion graphic interface for sm810/sm710/sm712 accelerator
|
||||
*
|
||||
* modification history
|
||||
* --------------------
|
||||
* 04-18-2002 Rewritten for U-Boot <fgottschling@eltec.de>.
|
||||
*
|
||||
* 18-03-2004 - Unify videomodes handling with the ct69000
|
||||
* - The video output can be set via the variable "videoout"
|
||||
* in the environment.
|
||||
* videoout=1 output on LCD
|
||||
* videoout=2 output on CRT (default value)
|
||||
* <p.aubert@staubli.com>
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
|
||||
#include <pci.h>
|
||||
#include <video_fb.h>
|
||||
#include "videomodes.h"
|
||||
/*
|
||||
* Export Graphic Device
|
||||
*/
|
||||
GraphicDevice smi;
|
||||
|
||||
/*
|
||||
* SMI 710/712 have 4MB internal RAM; SMI 810 2MB internal + 2MB external
|
||||
*/
|
||||
#define VIDEO_MEM_SIZE 0x400000
|
||||
|
||||
|
||||
/*
|
||||
* ISA mapped regs
|
||||
*/
|
||||
#define SMI_INDX_C4 (pGD->isaBase + 0x03c4) /* index reg */
|
||||
#define SMI_DATA_C5 (pGD->isaBase + 0x03c5) /* data reg */
|
||||
#define SMI_INDX_D4 (pGD->isaBase + 0x03d4) /* index reg */
|
||||
#define SMI_DATA_D5 (pGD->isaBase + 0x03d5) /* data reg */
|
||||
#define SMI_ISR1 (pGD->isaBase + 0x03ca)
|
||||
#define SMI_INDX_CE (pGD->isaBase + 0x03ce) /* index reg */
|
||||
#define SMI_DATA_CF (pGD->isaBase + 0x03cf) /* data reg */
|
||||
#define SMI_LOCK_REG (pGD->isaBase + 0x03c3) /* unlock/lock ext crt reg */
|
||||
#define SMI_MISC_REG (pGD->isaBase + 0x03c2) /* misc reg */
|
||||
#define SMI_LUT_MASK (pGD->isaBase + 0x03c6) /* lut mask reg */
|
||||
#define SMI_LUT_START (pGD->isaBase + 0x03c8) /* lut start index */
|
||||
#define SMI_LUT_RGB (pGD->isaBase + 0x03c9) /* lut colors auto incr.*/
|
||||
#define SMI_INDX_ATTR (pGD->isaBase + 0x03c0) /* attributes index reg */
|
||||
|
||||
/*
|
||||
* Video processor control
|
||||
*/
|
||||
typedef struct {
|
||||
unsigned int control;
|
||||
unsigned int colorKey;
|
||||
unsigned int colorKeyMask;
|
||||
unsigned int start;
|
||||
unsigned short offset;
|
||||
unsigned short width;
|
||||
unsigned int fifoPrio;
|
||||
unsigned int fifoERL;
|
||||
unsigned int YUVtoRGB;
|
||||
} SmiVideoProc;
|
||||
|
||||
/*
|
||||
* Video window control
|
||||
*/
|
||||
typedef struct {
|
||||
unsigned short top;
|
||||
unsigned short left;
|
||||
unsigned short bottom;
|
||||
unsigned short right;
|
||||
unsigned int srcStart;
|
||||
unsigned short width;
|
||||
unsigned short offset;
|
||||
unsigned char hStretch;
|
||||
unsigned char vStretch;
|
||||
} SmiVideoWin;
|
||||
|
||||
/*
|
||||
* Capture port control
|
||||
*/
|
||||
typedef struct {
|
||||
unsigned int control;
|
||||
unsigned short topClip;
|
||||
unsigned short leftClip;
|
||||
unsigned short srcHeight;
|
||||
unsigned short srcWidth;
|
||||
unsigned int srcBufStart1;
|
||||
unsigned int srcBufStart2;
|
||||
unsigned short srcOffset;
|
||||
unsigned short fifoControl;
|
||||
} SmiCapturePort;
|
||||
|
||||
|
||||
/*
|
||||
* Register values for common video modes
|
||||
*/
|
||||
static char SMI_SCR[] = {
|
||||
/* all modes */
|
||||
0x10, 0xff, 0x11, 0xff, 0x12, 0xff, 0x13, 0xff, 0x15, 0x90,
|
||||
0x17, 0x20, 0x18, 0xb1, 0x19, 0x00,
|
||||
};
|
||||
static char SMI_EXT_CRT[] = {
|
||||
0x31, 0x00, 0x32, 0x00, 0x33, 0x00, 0x34, 0x00, 0x35, 0x00,
|
||||
0x36, 0x00, 0x3b, 0x00, 0x3c, 0x00, 0x3d, 0x00, 0x3e, 0x00, 0x3f, 0x00,
|
||||
};
|
||||
static char SMI_ATTR [] = {
|
||||
0x00, 0x00, 0x01, 0x01, 0x02, 0x02, 0x03, 0x03, 0x04, 0x04, 0x05, 0x05,
|
||||
0x06, 0x06, 0x07, 0x07, 0x08, 0x08, 0x09, 0x09, 0x0a, 0x0a, 0x0b, 0x0b,
|
||||
0x0c, 0x0c, 0x0d, 0x0d, 0x0e, 0x0e, 0x0f, 0x0f, 0x10, 0x41, 0x11, 0x00,
|
||||
0x12, 0x0f, 0x13, 0x00, 0x14, 0x00,
|
||||
};
|
||||
static char SMI_GCR[18] = {
|
||||
0x00, 0x00, 0x01, 0x00, 0x02, 0x00, 0x03, 0x00, 0x04, 0x00, 0x05, 0x40,
|
||||
0x06, 0x05, 0x07, 0x0f, 0x08, 0xff,
|
||||
};
|
||||
static char SMI_SEQR[] = {
|
||||
0x00, 0x00, 0x01, 0x01, 0x02, 0x0f, 0x03, 0x03, 0x04, 0x0e, 0x00, 0x03,
|
||||
};
|
||||
static char SMI_PCR [] = {
|
||||
0x20, 0x04, 0x21, 0x30, 0x22, 0x00, 0x23, 0x00, 0x24, 0x00,
|
||||
};
|
||||
static char SMI_MCR[] = {
|
||||
0x60, 0x01, 0x61, 0x00,
|
||||
#ifdef CONFIG_HMI1001
|
||||
0x62, 0x74, /* Memory type is not configured by pins on HMI1001 */
|
||||
#endif
|
||||
};
|
||||
|
||||
static char SMI_HCR[] = {
|
||||
0x80, 0xff, 0x81, 0x07, 0x82, 0x00, 0x83, 0xff, 0x84, 0xff, 0x88, 0x00,
|
||||
0x89, 0x02, 0x8a, 0x80, 0x8b, 0x01, 0x8c, 0xff, 0x8d, 0x00,
|
||||
};
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
*
|
||||
* Write SMI ISA register
|
||||
*/
|
||||
static void smiWrite (unsigned short index, char reg, char val)
|
||||
{
|
||||
register GraphicDevice *pGD = (GraphicDevice *)&smi;
|
||||
|
||||
out8 ((pGD->isaBase + index), reg);
|
||||
out8 ((pGD->isaBase + index + 1), val);
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
*
|
||||
* Write a table of SMI ISA register
|
||||
*/
|
||||
static void smiLoadRegs (
|
||||
unsigned int iReg,
|
||||
unsigned int dReg,
|
||||
char *regTab,
|
||||
unsigned int tabSize
|
||||
)
|
||||
{
|
||||
register GraphicDevice *pGD = (GraphicDevice *)&smi;
|
||||
register int i;
|
||||
|
||||
for (i=0; i<tabSize; i+=2) {
|
||||
if (iReg == SMI_INDX_ATTR) {
|
||||
/* Reset the Flip Flop */
|
||||
in8 (SMI_ISR1);
|
||||
out8 (iReg, regTab[i]);
|
||||
out8 (iReg, regTab[i+1]);
|
||||
} else {
|
||||
out8 (iReg, regTab[i]);
|
||||
out8 (dReg, regTab[i+1]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
*
|
||||
* Init capture port registers
|
||||
*/
|
||||
static void smiInitCapturePort (void)
|
||||
{
|
||||
SmiCapturePort smiCP = { 0x01400600, 0x30, 0x40, 480, 640, 0, 0, 2560, 6 };
|
||||
register GraphicDevice *pGD = (GraphicDevice *)&smi;
|
||||
register SmiCapturePort *pCP = (SmiCapturePort *)&smiCP;
|
||||
|
||||
out32r ((pGD->cprBase + 0x0004), ((pCP->topClip<<16) | pCP->leftClip));
|
||||
out32r ((pGD->cprBase + 0x0008), ((pCP->srcHeight<<16) | pCP->srcWidth));
|
||||
out32r ((pGD->cprBase + 0x000c), pCP->srcBufStart1/8);
|
||||
out32r ((pGD->cprBase + 0x0010), pCP->srcBufStart2/8);
|
||||
out32r ((pGD->cprBase + 0x0014), pCP->srcOffset/8);
|
||||
out32r ((pGD->cprBase + 0x0018), pCP->fifoControl);
|
||||
out32r ((pGD->cprBase + 0x0000), pCP->control);
|
||||
}
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
*
|
||||
* Init video processor registers
|
||||
*/
|
||||
static void smiInitVideoProcessor (void)
|
||||
{
|
||||
SmiVideoProc smiVP = { 0x100000, 0, 0, 0, 0, 1600, 0x1200543, 4, 0xededed };
|
||||
SmiVideoWin smiVW = { 0, 0, 599, 799, 0, 1600, 0, 0, 0 };
|
||||
register GraphicDevice *pGD = (GraphicDevice *)&smi;
|
||||
register SmiVideoProc *pVP = (SmiVideoProc *)&smiVP;
|
||||
register SmiVideoWin *pVWin = (SmiVideoWin *)&smiVW;
|
||||
|
||||
pVP->width = pGD->plnSizeX * pGD->gdfBytesPP;
|
||||
pVP->control |= pGD->gdfIndex << 16;
|
||||
pVWin->bottom = pGD->winSizeY - 1;
|
||||
pVWin->right = pGD->winSizeX - 1;
|
||||
pVWin->width = pVP->width;
|
||||
|
||||
/* color key */
|
||||
out32r ((pGD->vprBase + 0x0004), pVP->colorKey);
|
||||
|
||||
/* color key mask */
|
||||
out32r ((pGD->vprBase + 0x0008), pVP->colorKeyMask);
|
||||
|
||||
/* data src start adrs */
|
||||
out32r ((pGD->vprBase + 0x000c), pVP->start / 8);
|
||||
|
||||
/* data width and offset */
|
||||
out32r ((pGD->vprBase + 0x0010),
|
||||
((pVP->offset / 8 * pGD->gdfBytesPP) << 16) |
|
||||
(pGD->plnSizeX / 8 * pGD->gdfBytesPP));
|
||||
|
||||
/* video window 1 */
|
||||
out32r ((pGD->vprBase + 0x0014),
|
||||
((pVWin->top << 16) | pVWin->left));
|
||||
|
||||
out32r ((pGD->vprBase + 0x0018),
|
||||
((pVWin->bottom << 16) | pVWin->right));
|
||||
|
||||
out32r ((pGD->vprBase + 0x001c), pVWin->srcStart / 8);
|
||||
|
||||
out32r ((pGD->vprBase + 0x0020),
|
||||
(((pVWin->offset / 8) << 16) | (pVWin->width / 8)));
|
||||
|
||||
out32r ((pGD->vprBase + 0x0024),
|
||||
(((pVWin->hStretch) << 8) | pVWin->vStretch));
|
||||
|
||||
/* video window 2 */
|
||||
out32r ((pGD->vprBase + 0x0028),
|
||||
((pVWin->top << 16) | pVWin->left));
|
||||
|
||||
out32r ((pGD->vprBase + 0x002c),
|
||||
((pVWin->bottom << 16) | pVWin->right));
|
||||
|
||||
out32r ((pGD->vprBase + 0x0030),
|
||||
pVWin->srcStart / 8);
|
||||
|
||||
out32r ((pGD->vprBase + 0x0034),
|
||||
(((pVWin->offset / 8) << 16) | (pVWin->width / 8)));
|
||||
|
||||
out32r ((pGD->vprBase + 0x0038),
|
||||
(((pVWin->hStretch) << 8) | pVWin->vStretch));
|
||||
|
||||
/* fifo prio control */
|
||||
out32r ((pGD->vprBase + 0x0054), pVP->fifoPrio);
|
||||
|
||||
/* fifo empty request levell */
|
||||
out32r ((pGD->vprBase + 0x0058), pVP->fifoERL);
|
||||
|
||||
/* conversion constant */
|
||||
out32r ((pGD->vprBase + 0x005c), pVP->YUVtoRGB);
|
||||
|
||||
/* vpr control word */
|
||||
out32r ((pGD->vprBase + 0x0000), pVP->control);
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
*
|
||||
* Init drawing engine registers
|
||||
*/
|
||||
static void smiInitDrawingEngine (void)
|
||||
{
|
||||
GraphicDevice *pGD = (GraphicDevice *)&smi;
|
||||
unsigned int val;
|
||||
|
||||
/* don't start now */
|
||||
out32r ((pGD->dprBase + 0x000c), 0x000f0000);
|
||||
|
||||
/* set rop2 to copypen */
|
||||
val = 0xffff3ff0 & in32r ((pGD->dprBase + 0x000c));
|
||||
out32r ((pGD->dprBase + 0x000c), (val | 0x8000 | 0x0c));
|
||||
|
||||
/* set clip rect */
|
||||
out32r ((pGD->dprBase + 0x002c), 0);
|
||||
out32r ((pGD->dprBase + 0x0030),
|
||||
((pGD->winSizeY<<16) | pGD->winSizeX * pGD->gdfBytesPP ));
|
||||
|
||||
/* src row pitch */
|
||||
val = 0xffff0000 & (in32r ((pGD->dprBase + 0x0010)));
|
||||
out32r ((pGD->dprBase + 0x0010),
|
||||
(val | pGD->plnSizeX * pGD->gdfBytesPP));
|
||||
|
||||
/* dst row pitch */
|
||||
val = 0x0000ffff & (in32r ((pGD->dprBase + 0x0010)));
|
||||
out32r ((pGD->dprBase + 0x0010),
|
||||
(((pGD->plnSizeX * pGD->gdfBytesPP)<<16) | val));
|
||||
|
||||
/* window width src/dst */
|
||||
out32r ((pGD->dprBase + 0x003c),
|
||||
(((pGD->plnSizeX * pGD->gdfBytesPP & 0x0fff)<<16) |
|
||||
(pGD->plnSizeX * pGD->gdfBytesPP & 0x0fff)));
|
||||
out16r ((pGD->dprBase + 0x001e), 0x0000);
|
||||
|
||||
/* src base adrs */
|
||||
out32r ((pGD->dprBase + 0x0040),
|
||||
(((pGD->frameAdrs/8) & 0x000fffff)));
|
||||
|
||||
/* dst base adrs */
|
||||
out32r ((pGD->dprBase + 0x0044),
|
||||
(((pGD->frameAdrs/8) & 0x000fffff)));
|
||||
|
||||
/* foreground color */
|
||||
out32r ((pGD->dprBase + 0x0014), pGD->fg);
|
||||
|
||||
/* background color */
|
||||
out32r ((pGD->dprBase + 0x0018), pGD->bg);
|
||||
|
||||
/* xcolor */
|
||||
out32r ((pGD->dprBase + 0x0020), 0x00ffffff);
|
||||
|
||||
/* xcolor mask */
|
||||
out32r ((pGD->dprBase + 0x0024), 0x00ffffff);
|
||||
|
||||
/* bit mask */
|
||||
out32r ((pGD->dprBase + 0x0028), 0x00ffffff);
|
||||
|
||||
/* load mono pattern */
|
||||
out32r ((pGD->dprBase + 0x0034), 0);
|
||||
out32r ((pGD->dprBase + 0x0038), 0);
|
||||
}
|
||||
|
||||
static struct pci_device_id supported[] = {
|
||||
{ PCI_VENDOR_ID_SMI, PCI_DEVICE_ID_SMI_710 },
|
||||
{ PCI_VENDOR_ID_SMI, PCI_DEVICE_ID_SMI_712 },
|
||||
{ PCI_VENDOR_ID_SMI, PCI_DEVICE_ID_SMI_810 },
|
||||
{ }
|
||||
};
|
||||
|
||||
/*****************************************************************************/
|
||||
static void smiLoadMsr (struct ctfb_res_modes *mode)
|
||||
{
|
||||
unsigned char h_synch_high, v_synch_high;
|
||||
register GraphicDevice *pGD = (GraphicDevice *)&smi;
|
||||
|
||||
h_synch_high = (mode->sync & FB_SYNC_HOR_HIGH_ACT) ? 0 : 0x40; /* horizontal Synch High active */
|
||||
v_synch_high = (mode->sync & FB_SYNC_VERT_HIGH_ACT) ? 0 : 0x80; /* vertical Synch High active */
|
||||
out8 (SMI_MISC_REG, (h_synch_high | v_synch_high | 0x29));
|
||||
/* upper64K==0x20, CLC2select==0x08, RAMenable==0x02!(todo), CGA==0x01
|
||||
* Selects the upper 64KB page.Bit5=1
|
||||
* CLK2 (left reserved in standard VGA) Bit3|2=1|0
|
||||
* Disables CPU access to frame buffer. Bit1=0
|
||||
* Sets the I/O address decode for ST01, FCR, and all CR registers
|
||||
* to the 3Dx I/O address range (CGA emulation). Bit0=1
|
||||
*/
|
||||
}
|
||||
/*****************************************************************************/
|
||||
static void smiLoadCrt (struct ctfb_res_modes *var, int bits_per_pixel)
|
||||
{
|
||||
unsigned char cr[0x7a];
|
||||
int i;
|
||||
unsigned int hd, hs, he, ht, hbs, hbe; /* Horizontal. */
|
||||
unsigned int vd, vs, ve, vt, vbs, vbe; /* vertical */
|
||||
unsigned int bpp, wd, dblscan, interlaced;
|
||||
|
||||
const int LineCompare = 0x3ff;
|
||||
unsigned int TextScanLines = 1; /* this is in fact a vertical zoom factor */
|
||||
register GraphicDevice *pGD = (GraphicDevice *)&smi;
|
||||
|
||||
/* Horizontal */
|
||||
hd = (var->xres) / 8; /* HDisp. */
|
||||
hs = (var->xres + var->right_margin) / 8; /* HsStrt */
|
||||
he = (var->xres + var->right_margin + var->hsync_len) / 8; /* HsEnd */
|
||||
ht = (var->left_margin + var->xres + var->right_margin + var->hsync_len) / 8; /* HTotal */
|
||||
/* Blank */
|
||||
hbs = hd;
|
||||
hbe = 0; /* Blank end at 0 */
|
||||
|
||||
/* Vertical */
|
||||
vd = var->yres; /* VDisplay */
|
||||
vs = var->yres + var->lower_margin; /* VSyncStart */
|
||||
ve = var->yres + var->lower_margin + var->vsync_len; /* VSyncEnd */
|
||||
vt = var->upper_margin + var->yres + var->lower_margin + var->vsync_len; /* VTotal */
|
||||
vbs = vd;
|
||||
vbe = 0;
|
||||
|
||||
bpp = bits_per_pixel;
|
||||
dblscan = (var->vmode & FB_VMODE_DOUBLE) ? 1 : 0;
|
||||
interlaced = var->vmode & FB_VMODE_INTERLACED;
|
||||
|
||||
|
||||
if (bpp == 15)
|
||||
bpp = 16;
|
||||
wd = var->xres * bpp / 64; /* double words per line */
|
||||
if (interlaced) { /* we divide all vertical timings, exept vd */
|
||||
vs >>= 1;
|
||||
vbs >>= 1;
|
||||
ve >>= 1;
|
||||
vt >>= 1;
|
||||
}
|
||||
|
||||
memset (cr, 0, sizeof (cr));
|
||||
cr[0x00] = ht - 5;
|
||||
cr[0x01] = hd - 1;
|
||||
cr[0x02] = hbs - 1;
|
||||
cr[0x03] = (hbe & 0x1F);
|
||||
cr[0x04] = hs;
|
||||
cr[0x05] = ((hbe & 0x20) << 2) | (he & 0x1f);
|
||||
|
||||
cr[0x06] = (vt - 2) & 0xFF;
|
||||
cr[0x07] = (((vt - 2) & 0x100) >> 8)
|
||||
| (((vd - 1) & 0x100) >> 7)
|
||||
| ((vs & 0x100) >> 6)
|
||||
| (((vbs - 1) & 0x100) >> 5)
|
||||
| ((LineCompare & 0x100) >> 4)
|
||||
| (((vt - 2) & 0x200) >> 4)
|
||||
| (((vd - 1) & 0x200) >> 3)
|
||||
| ((vs & 0x200) >> 2);
|
||||
|
||||
cr[0x30] = ((vt - 2) & 0x400) >> 7
|
||||
| (((vd - 1) & 0x400) >> 8)
|
||||
| (((vbs - 1) & 0x400) >> 9)
|
||||
| ((vs & 0x400) >> 10)
|
||||
| (interlaced) ? 0x80 : 0;
|
||||
|
||||
|
||||
cr[0x08] = 0x00;
|
||||
cr[0x09] = (dblscan << 7)
|
||||
| ((LineCompare & 0x200) >> 3)
|
||||
| (((vbs - 1) & 0x200) >> 4)
|
||||
| (TextScanLines - 1);
|
||||
|
||||
cr[0x10] = vs & 0xff; /* VSyncPulseStart */
|
||||
cr[0x11] = (ve & 0x0f);
|
||||
cr[0x12] = (vd - 1) & 0xff; /* LineCount */
|
||||
cr[0x13] = wd & 0xff;
|
||||
cr[0x14] = 0x40;
|
||||
cr[0x15] = (vbs - 1) & 0xff;
|
||||
cr[0x16] = vbe & 0xff;
|
||||
cr[0x17] = 0xe3; /* but it does not work */
|
||||
cr[0x18] = 0xff & LineCompare;
|
||||
cr[0x22] = 0x00; /* todo? */
|
||||
|
||||
|
||||
/* now set the registers */
|
||||
for (i = 0; i <= 0x18; i++) { /*CR00 .. CR18 */
|
||||
smiWrite (SMI_INDX_D4, i, cr[i]);
|
||||
}
|
||||
i = 0x22; /*CR22 */
|
||||
smiWrite (SMI_INDX_D4, i, cr[i]);
|
||||
i = 0x30; /*CR30 */
|
||||
smiWrite (SMI_INDX_D4, i, cr[i]);
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
#define REF_FREQ 14318180
|
||||
#define PMIN 1
|
||||
#define PMAX 255
|
||||
#define QMIN 1
|
||||
#define QMAX 63
|
||||
|
||||
static unsigned int FindPQ (unsigned int freq, unsigned int *pp, unsigned int *pq)
|
||||
{
|
||||
unsigned int n = QMIN, m = 0;
|
||||
long long int L = 0, P = freq, Q = REF_FREQ, H = P >> 1;
|
||||
long long int D = 0x7ffffffffffffffLL;
|
||||
|
||||
for (n = QMIN; n <= QMAX; n++) {
|
||||
m = PMIN; /* p/q ~ freq/ref -> p*ref-freq*q ~ 0 */
|
||||
L = P * n - m * Q;
|
||||
while (L > 0 && m < PMAX) {
|
||||
L -= REF_FREQ; /* difference is greater as 0 subtract fref */
|
||||
m++; /* and increment m */
|
||||
}
|
||||
/* difference is less or equal than 0 or m > maximum */
|
||||
if (m > PMAX)
|
||||
break; /* no solution: if we increase n we get the same situation */
|
||||
/* L is <= 0 now */
|
||||
if (-L > H && m > PMIN) { /* if difference > the half fref */
|
||||
L += REF_FREQ; /* we take the situation before */
|
||||
m--; /* because its closer to 0 */
|
||||
}
|
||||
L = (L < 0) ? -L : +L; /* absolute value */
|
||||
if (D < L) /* if last difference was better take next n */
|
||||
continue;
|
||||
D = L;
|
||||
*pp = m;
|
||||
*pq = n; /* keep improved data */
|
||||
if (D == 0)
|
||||
break; /* best result we can get */
|
||||
}
|
||||
return (unsigned int) (0xffffffff & D);
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
static void smiLoadCcr (struct ctfb_res_modes *var, unsigned short device_id)
|
||||
{
|
||||
unsigned int p = 0;
|
||||
unsigned int q = 0;
|
||||
long long freq;
|
||||
register GraphicDevice *pGD = (GraphicDevice *)&smi;
|
||||
|
||||
smiWrite (SMI_INDX_C4, 0x65, 0);
|
||||
smiWrite (SMI_INDX_C4, 0x66, 0);
|
||||
smiWrite (SMI_INDX_C4, 0x68, 0x50);
|
||||
if (device_id == PCI_DEVICE_ID_SMI_810) {
|
||||
smiWrite (SMI_INDX_C4, 0x69, 0x3);
|
||||
} else {
|
||||
smiWrite (SMI_INDX_C4, 0x69, 0x0);
|
||||
}
|
||||
|
||||
/* Memory clock */
|
||||
switch (device_id) {
|
||||
case PCI_DEVICE_ID_SMI_710 :
|
||||
smiWrite (SMI_INDX_C4, 0x6a, 0x75);
|
||||
break;
|
||||
case PCI_DEVICE_ID_SMI_712 :
|
||||
smiWrite (SMI_INDX_C4, 0x6a, 0x80);
|
||||
break;
|
||||
default :
|
||||
smiWrite (SMI_INDX_C4, 0x6a, 0x53);
|
||||
break;
|
||||
}
|
||||
smiWrite (SMI_INDX_C4, 0x6b, 0x15);
|
||||
|
||||
/* VCLK */
|
||||
freq = 1000000000000LL / var -> pixclock;
|
||||
|
||||
FindPQ ((unsigned int)freq, &p, &q);
|
||||
|
||||
smiWrite (SMI_INDX_C4, 0x6c, p);
|
||||
smiWrite (SMI_INDX_C4, 0x6d, q);
|
||||
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
*
|
||||
* Init video chip with common Linux graphic modes (lilo)
|
||||
*/
|
||||
void *video_hw_init (void)
|
||||
{
|
||||
GraphicDevice *pGD = (GraphicDevice *)&smi;
|
||||
unsigned short device_id;
|
||||
pci_dev_t devbusfn;
|
||||
int videomode;
|
||||
unsigned long t1, hsynch, vsynch;
|
||||
unsigned int pci_mem_base, *vm;
|
||||
char *penv;
|
||||
int tmp, i, bits_per_pixel;
|
||||
struct ctfb_res_modes *res_mode;
|
||||
struct ctfb_res_modes var_mode;
|
||||
unsigned char videoout;
|
||||
|
||||
/* Search for video chip */
|
||||
printf("Video: ");
|
||||
|
||||
if ((devbusfn = pci_find_devices(supported, 0)) < 0)
|
||||
{
|
||||
printf ("Controller not found !\n");
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
/* PCI setup */
|
||||
pci_write_config_dword (devbusfn, PCI_COMMAND, (PCI_COMMAND_MEMORY | PCI_COMMAND_IO));
|
||||
pci_read_config_word (devbusfn, PCI_DEVICE_ID, &device_id);
|
||||
pci_read_config_dword (devbusfn, PCI_BASE_ADDRESS_0, &pci_mem_base);
|
||||
pci_mem_base = pci_mem_to_phys (devbusfn, pci_mem_base);
|
||||
|
||||
tmp = 0;
|
||||
|
||||
videomode = CONFIG_SYS_DEFAULT_VIDEO_MODE;
|
||||
/* get video mode via environment */
|
||||
if ((penv = getenv ("videomode")) != NULL) {
|
||||
/* deceide if it is a string */
|
||||
if (penv[0] <= '9') {
|
||||
videomode = (int) simple_strtoul (penv, NULL, 16);
|
||||
tmp = 1;
|
||||
}
|
||||
} else {
|
||||
tmp = 1;
|
||||
}
|
||||
if (tmp) {
|
||||
/* parameter are vesa modes */
|
||||
/* search params */
|
||||
for (i = 0; i < VESA_MODES_COUNT; i++) {
|
||||
if (vesa_modes[i].vesanr == videomode)
|
||||
break;
|
||||
}
|
||||
if (i == VESA_MODES_COUNT) {
|
||||
printf ("no VESA Mode found, switching to mode 0x%x ", CONFIG_SYS_DEFAULT_VIDEO_MODE);
|
||||
i = 0;
|
||||
}
|
||||
res_mode =
|
||||
(struct ctfb_res_modes *) &res_mode_init[vesa_modes[i].
|
||||
resindex];
|
||||
bits_per_pixel = vesa_modes[i].bits_per_pixel;
|
||||
} else {
|
||||
|
||||
res_mode = (struct ctfb_res_modes *) &var_mode;
|
||||
bits_per_pixel = video_get_params (res_mode, penv);
|
||||
}
|
||||
|
||||
/* calculate hsynch and vsynch freq (info only) */
|
||||
t1 = (res_mode->left_margin + res_mode->xres +
|
||||
res_mode->right_margin + res_mode->hsync_len) / 8;
|
||||
t1 *= 8;
|
||||
t1 *= res_mode->pixclock;
|
||||
t1 /= 1000;
|
||||
hsynch = 1000000000L / t1;
|
||||
t1 *=
|
||||
(res_mode->upper_margin + res_mode->yres +
|
||||
res_mode->lower_margin + res_mode->vsync_len);
|
||||
t1 /= 1000;
|
||||
vsynch = 1000000000L / t1;
|
||||
|
||||
/* fill in Graphic device struct */
|
||||
sprintf (pGD->modeIdent, "%dx%dx%d %ldkHz %ldHz", res_mode->xres,
|
||||
res_mode->yres, bits_per_pixel, (hsynch / 1000),
|
||||
(vsynch / 1000));
|
||||
printf ("%s\n", pGD->modeIdent);
|
||||
pGD->winSizeX = res_mode->xres;
|
||||
pGD->winSizeY = res_mode->yres;
|
||||
pGD->plnSizeX = res_mode->xres;
|
||||
pGD->plnSizeY = res_mode->yres;
|
||||
switch (bits_per_pixel) {
|
||||
case 8:
|
||||
pGD->gdfBytesPP = 1;
|
||||
pGD->gdfIndex = GDF__8BIT_INDEX;
|
||||
break;
|
||||
case 15:
|
||||
pGD->gdfBytesPP = 2;
|
||||
pGD->gdfIndex = GDF_15BIT_555RGB;
|
||||
break;
|
||||
case 16:
|
||||
pGD->gdfBytesPP = 2;
|
||||
pGD->gdfIndex = GDF_16BIT_565RGB;
|
||||
break;
|
||||
case 24:
|
||||
pGD->gdfBytesPP = 3;
|
||||
pGD->gdfIndex = GDF_24BIT_888RGB;
|
||||
break;
|
||||
}
|
||||
|
||||
pGD->isaBase = CONFIG_SYS_ISA_IO;
|
||||
pGD->pciBase = pci_mem_base;
|
||||
pGD->dprBase = (pci_mem_base + 0x400000 + 0x8000);
|
||||
pGD->vprBase = (pci_mem_base + 0x400000 + 0xc000);
|
||||
pGD->cprBase = (pci_mem_base + 0x400000 + 0xe000);
|
||||
pGD->frameAdrs = pci_mem_base;
|
||||
pGD->memSize = VIDEO_MEM_SIZE;
|
||||
|
||||
/* Set up hardware : select color mode,
|
||||
set Register base to isa 3dx for 3?x regs*/
|
||||
out8 (SMI_MISC_REG, 0x01);
|
||||
|
||||
/* Turn off display */
|
||||
smiWrite (SMI_INDX_C4, 0x01, 0x20);
|
||||
|
||||
/* Unlock ext. crt regs */
|
||||
out8 (SMI_LOCK_REG, 0x40);
|
||||
|
||||
/* Unlock crt regs 0-7 */
|
||||
smiWrite (SMI_INDX_D4, 0x11, 0x0e);
|
||||
|
||||
/* Sytem Control Register */
|
||||
smiLoadRegs (SMI_INDX_C4, SMI_DATA_C5, SMI_SCR, sizeof(SMI_SCR));
|
||||
|
||||
/* extented CRT Register */
|
||||
smiLoadRegs (SMI_INDX_D4, SMI_DATA_D5, SMI_EXT_CRT, sizeof(SMI_EXT_CRT));
|
||||
|
||||
/* Attributes controller registers */
|
||||
smiLoadRegs (SMI_INDX_ATTR, SMI_INDX_ATTR, SMI_ATTR, sizeof(SMI_ATTR));
|
||||
|
||||
/* Graphics Controller Register */
|
||||
smiLoadRegs (SMI_INDX_CE, SMI_DATA_CF, SMI_GCR, sizeof(SMI_GCR));
|
||||
|
||||
/* Sequencer Register */
|
||||
smiLoadRegs (SMI_INDX_C4, SMI_DATA_C5, SMI_SEQR, sizeof(SMI_SEQR));
|
||||
|
||||
/* Power Control Register */
|
||||
smiLoadRegs (SMI_INDX_C4, SMI_DATA_C5, SMI_PCR, sizeof(SMI_PCR));
|
||||
|
||||
/* Memory Control Register */
|
||||
/* Register MSR62 is a power on configurable register. We don't */
|
||||
/* modify it */
|
||||
smiLoadRegs (SMI_INDX_C4, SMI_DATA_C5, SMI_MCR, sizeof(SMI_MCR));
|
||||
|
||||
/* Set misc output register */
|
||||
smiLoadMsr (res_mode);
|
||||
|
||||
/* Set CRT and Clock control registers */
|
||||
smiLoadCrt (res_mode, bits_per_pixel);
|
||||
|
||||
smiLoadCcr (res_mode, device_id);
|
||||
|
||||
/* Hardware Cusor Register */
|
||||
smiLoadRegs (SMI_INDX_C4, SMI_DATA_C5, SMI_HCR, sizeof(SMI_HCR));
|
||||
|
||||
/* Enable Display */
|
||||
videoout = 2; /* Default output is CRT */
|
||||
if ((penv = getenv ("videoout")) != NULL) {
|
||||
/* deceide if it is a string */
|
||||
videoout = (int) simple_strtoul (penv, NULL, 16);
|
||||
}
|
||||
smiWrite (SMI_INDX_C4, 0x31, videoout);
|
||||
|
||||
/* Video processor default setup */
|
||||
smiInitVideoProcessor ();
|
||||
|
||||
/* Capture port default setup */
|
||||
smiInitCapturePort ();
|
||||
|
||||
/* Drawing engine default setup */
|
||||
smiInitDrawingEngine ();
|
||||
|
||||
/* Turn on display */
|
||||
smiWrite (0x3c4, 0x01, 0x01);
|
||||
|
||||
/* Clear video memory */
|
||||
i = pGD->memSize/4;
|
||||
vm = (unsigned int *)pGD->pciBase;
|
||||
while(i--)
|
||||
*vm++ = 0;
|
||||
return ((void*)&smi);
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
*
|
||||
* Drawing engine fill on screen region
|
||||
*/
|
||||
void video_hw_rectfill (
|
||||
unsigned int bpp, /* bytes per pixel */
|
||||
unsigned int dst_x, /* dest pos x */
|
||||
unsigned int dst_y, /* dest pos y */
|
||||
unsigned int dim_x, /* frame width */
|
||||
unsigned int dim_y, /* frame height */
|
||||
unsigned int color /* fill color */
|
||||
)
|
||||
{
|
||||
register GraphicDevice *pGD = (GraphicDevice *)&smi;
|
||||
register unsigned int control;
|
||||
|
||||
dim_x *= bpp;
|
||||
|
||||
out32r ((pGD->dprBase + 0x0014), color);
|
||||
out32r ((pGD->dprBase + 0x0004), ((dst_x<<16) | dst_y));
|
||||
out32r ((pGD->dprBase + 0x0008), ((dim_x<<16) | dim_y));
|
||||
|
||||
control = 0x0000ffff & in32r ((pGD->dprBase + 0x000c));
|
||||
|
||||
control |= 0x80010000;
|
||||
|
||||
out32r ((pGD->dprBase + 0x000c), control);
|
||||
|
||||
/* Wait for drawing processor */
|
||||
do
|
||||
{
|
||||
out8 ((pGD->isaBase + 0x3c4), 0x16);
|
||||
} while (in8 (pGD->isaBase + 0x3c5) & 0x08);
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
*
|
||||
* Drawing engine bitblt with screen region
|
||||
*/
|
||||
void video_hw_bitblt (
|
||||
unsigned int bpp, /* bytes per pixel */
|
||||
unsigned int src_x, /* source pos x */
|
||||
unsigned int src_y, /* source pos y */
|
||||
unsigned int dst_x, /* dest pos x */
|
||||
unsigned int dst_y, /* dest pos y */
|
||||
unsigned int dim_x, /* frame width */
|
||||
unsigned int dim_y /* frame height */
|
||||
)
|
||||
{
|
||||
register GraphicDevice *pGD = (GraphicDevice *)&smi;
|
||||
register unsigned int control;
|
||||
|
||||
dim_x *= bpp;
|
||||
|
||||
if ((src_y<dst_y) || ((src_y==dst_y) && (src_x<dst_x)))
|
||||
{
|
||||
out32r ((pGD->dprBase + 0x0000), (((src_x+dim_x-1)<<16) | (src_y+dim_y-1)));
|
||||
out32r ((pGD->dprBase + 0x0004), (((dst_x+dim_x-1)<<16) | (dst_y+dim_y-1)));
|
||||
control = 0x88000000;
|
||||
} else {
|
||||
out32r ((pGD->dprBase + 0x0000), ((src_x<<16) | src_y));
|
||||
out32r ((pGD->dprBase + 0x0004), ((dst_x<<16) | dst_y));
|
||||
control = 0x80000000;
|
||||
}
|
||||
|
||||
out32r ((pGD->dprBase + 0x0008), ((dim_x<<16) | dim_y));
|
||||
control |= (0x0000ffff & in32r ((pGD->dprBase + 0x000c)));
|
||||
out32r ((pGD->dprBase + 0x000c), control);
|
||||
|
||||
/* Wait for drawing processor */
|
||||
do
|
||||
{
|
||||
out8 ((pGD->isaBase + 0x3c4), 0x16);
|
||||
} while (in8 (pGD->isaBase + 0x3c5) & 0x08);
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
*
|
||||
* Set a RGB color in the LUT (8 bit index)
|
||||
*/
|
||||
void video_set_lut (
|
||||
unsigned int index, /* color number */
|
||||
unsigned char r, /* red */
|
||||
unsigned char g, /* green */
|
||||
unsigned char b /* blue */
|
||||
)
|
||||
{
|
||||
register GraphicDevice *pGD = (GraphicDevice *)&smi;
|
||||
|
||||
out8 (SMI_LUT_MASK, 0xff);
|
||||
|
||||
out8 (SMI_LUT_START, (char)index);
|
||||
|
||||
out8 (SMI_LUT_RGB, r>>2); /* red */
|
||||
udelay (10);
|
||||
out8 (SMI_LUT_RGB, g>>2); /* green */
|
||||
udelay (10);
|
||||
out8 (SMI_LUT_RGB, b>>2); /* blue */
|
||||
udelay (10);
|
||||
}
|
||||
278
common/package/boot/uboot-ipq40xx/src/drivers/video/videomodes.c
Normal file
278
common/package/boot/uboot-ipq40xx/src/drivers/video/videomodes.c
Normal file
|
|
@ -0,0 +1,278 @@
|
|||
/*
|
||||
* (C) Copyright 2004
|
||||
* Pierre Aubert, Staubli Faverges , <p.aubert@staubli.com>
|
||||
* Copyright 2011 Freescale Semiconductor, Inc.
|
||||
*
|
||||
* See file CREDITS for list of people who contributed to this
|
||||
* project.
|
||||
*
|
||||
* 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
|
||||
*/
|
||||
|
||||
/************************************************************************
|
||||
Get Parameters for the video mode:
|
||||
The default video mode can be defined in CONFIG_SYS_DEFAULT_VIDEO_MODE.
|
||||
If undefined, default video mode is set to 0x301
|
||||
Parameters can be set via the variable "videomode" in the environment.
|
||||
2 diferent ways are possible:
|
||||
"videomode=301" - 301 is a hexadecimal number describing the VESA
|
||||
mode. Following modes are implemented:
|
||||
|
||||
Colors 640x480 800x600 1024x768 1152x864 1280x1024
|
||||
--------+---------------------------------------------
|
||||
8 bits | 0x301 0x303 0x305 0x161 0x307
|
||||
15 bits | 0x310 0x313 0x316 0x162 0x319
|
||||
16 bits | 0x311 0x314 0x317 0x163 0x31A
|
||||
24 bits | 0x312 0x315 0x318 ? 0x31B
|
||||
--------+---------------------------------------------
|
||||
"videomode=bootargs"
|
||||
- the parameters are parsed from the bootargs.
|
||||
The format is "NAME:VALUE,NAME:VALUE" etc.
|
||||
Ex.:
|
||||
"bootargs=video=ctfb:x:800,y:600,depth:16,pclk:25000"
|
||||
Parameters not included in the list will be taken from
|
||||
the default mode, which is one of the following:
|
||||
mode:0 640x480x24
|
||||
mode:1 800x600x16
|
||||
mode:2 1024x768x8
|
||||
mode:3 960x720x24
|
||||
mode:4 1152x864x16
|
||||
mode:5 1280x1024x8
|
||||
|
||||
if "mode" is not provided within the parameter list,
|
||||
mode:0 is assumed.
|
||||
Following parameters are supported:
|
||||
x xres = visible resolution horizontal
|
||||
y yres = visible resolution vertical
|
||||
pclk pixelclocks in pico sec
|
||||
le left_marging time from sync to picture in pixelclocks
|
||||
ri right_marging time from picture to sync in pixelclocks
|
||||
up upper_margin time from sync to picture
|
||||
lo lower_margin
|
||||
hs hsync_len length of horizontal sync
|
||||
vs vsync_len length of vertical sync
|
||||
sync see FB_SYNC_*
|
||||
vmode see FB_VMODE_*
|
||||
depth Color depth in bits per pixel
|
||||
All other parameters in the variable bootargs are ignored.
|
||||
It is also possible to set the parameters direct in the
|
||||
variable "videomode", or in another variable i.e.
|
||||
"myvideo" and setting the variable "videomode=myvideo"..
|
||||
****************************************************************************/
|
||||
|
||||
#include <common.h>
|
||||
#include <linux/ctype.h>
|
||||
|
||||
#include "videomodes.h"
|
||||
|
||||
const struct ctfb_vesa_modes vesa_modes[VESA_MODES_COUNT] = {
|
||||
{0x301, RES_MODE_640x480, 8},
|
||||
{0x310, RES_MODE_640x480, 15},
|
||||
{0x311, RES_MODE_640x480, 16},
|
||||
{0x312, RES_MODE_640x480, 24},
|
||||
{0x303, RES_MODE_800x600, 8},
|
||||
{0x313, RES_MODE_800x600, 15},
|
||||
{0x314, RES_MODE_800x600, 16},
|
||||
{0x315, RES_MODE_800x600, 24},
|
||||
{0x305, RES_MODE_1024x768, 8},
|
||||
{0x316, RES_MODE_1024x768, 15},
|
||||
{0x317, RES_MODE_1024x768, 16},
|
||||
{0x318, RES_MODE_1024x768, 24},
|
||||
{0x161, RES_MODE_1152x864, 8},
|
||||
{0x162, RES_MODE_1152x864, 15},
|
||||
{0x163, RES_MODE_1152x864, 16},
|
||||
{0x307, RES_MODE_1280x1024, 8},
|
||||
{0x319, RES_MODE_1280x1024, 15},
|
||||
{0x31A, RES_MODE_1280x1024, 16},
|
||||
{0x31B, RES_MODE_1280x1024, 24},
|
||||
};
|
||||
const struct ctfb_res_modes res_mode_init[RES_MODES_COUNT] = {
|
||||
/* x y pixclk le ri up lo hs vs s vmode */
|
||||
{640, 480, 39721, 40, 24, 32, 11, 96, 2, 0, FB_VMODE_NONINTERLACED},
|
||||
{800, 600, 27778, 64, 24, 22, 1, 72, 2, 0, FB_VMODE_NONINTERLACED},
|
||||
{1024, 768, 15384, 168, 8, 29, 3, 144, 4, 0, FB_VMODE_NONINTERLACED},
|
||||
{960, 720, 13100, 160, 40, 32, 8, 80, 4, 0, FB_VMODE_NONINTERLACED},
|
||||
{1152, 864, 12004, 200, 64, 32, 16, 80, 4, 0, FB_VMODE_NONINTERLACED},
|
||||
{1280, 1024, 9090, 200, 48, 26, 1, 184, 3, 0, FB_VMODE_NONINTERLACED},
|
||||
};
|
||||
|
||||
/************************************************************************
|
||||
* Get Parameters for the video mode:
|
||||
*/
|
||||
/*********************************************************************
|
||||
* returns the length to the next seperator
|
||||
*/
|
||||
static int
|
||||
video_get_param_len (char *start, char sep)
|
||||
{
|
||||
int i = 0;
|
||||
while ((*start != 0) && (*start != sep)) {
|
||||
start++;
|
||||
i++;
|
||||
}
|
||||
return i;
|
||||
}
|
||||
|
||||
static int
|
||||
video_search_param (char *start, char *param)
|
||||
{
|
||||
int len, totallen, i;
|
||||
char *p = start;
|
||||
len = strlen (param);
|
||||
totallen = len + strlen (start);
|
||||
for (i = 0; i < totallen; i++) {
|
||||
if (strncmp (p++, param, len) == 0)
|
||||
return (i);
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
/***************************************************************
|
||||
* Get parameter via the environment as it is done for the
|
||||
* linux kernel i.e:
|
||||
* video=ctfb:x:800,xv:1280,y:600,yv:1024,depth:16,mode:0,pclk:25000,
|
||||
* le:56,ri:48,up:26,lo:5,hs:152,vs:2,sync:0,vmode:0,accel:0
|
||||
*
|
||||
* penv is a pointer to the environment, containing the string, or the name of
|
||||
* another environment variable. It could even be the term "bootargs"
|
||||
*/
|
||||
|
||||
#define GET_OPTION(name,var) \
|
||||
if(strncmp(p,name,strlen(name))==0) { \
|
||||
val_s=p+strlen(name); \
|
||||
var=simple_strtoul(val_s, NULL, 10); \
|
||||
}
|
||||
|
||||
int video_get_params (struct ctfb_res_modes *pPar, char *penv)
|
||||
{
|
||||
char *p, *s, *val_s;
|
||||
int i = 0;
|
||||
int bpp;
|
||||
int mode;
|
||||
|
||||
/* first search for the environment containing the real param string */
|
||||
s = penv;
|
||||
|
||||
if ((p = getenv (s)) != NULL)
|
||||
s = p;
|
||||
|
||||
/*
|
||||
* in case of the bootargs line, we have to start
|
||||
* after "video=ctfb:"
|
||||
*/
|
||||
i = video_search_param (s, "video=ctfb:");
|
||||
if (i >= 0) {
|
||||
s += i;
|
||||
s += strlen ("video=ctfb:");
|
||||
}
|
||||
/* search for mode as a default value */
|
||||
p = s;
|
||||
mode = 0; /* default */
|
||||
|
||||
while ((i = video_get_param_len (p, ',')) != 0) {
|
||||
GET_OPTION ("mode:", mode)
|
||||
p += i;
|
||||
if (*p != 0)
|
||||
p++; /* skip ',' */
|
||||
}
|
||||
|
||||
if (mode >= RES_MODES_COUNT)
|
||||
mode = 0;
|
||||
|
||||
*pPar = res_mode_init[mode]; /* copy default values */
|
||||
bpp = 24 - ((mode % 3) * 8);
|
||||
p = s; /* restart */
|
||||
|
||||
while ((i = video_get_param_len (p, ',')) != 0) {
|
||||
GET_OPTION ("x:", pPar->xres)
|
||||
GET_OPTION ("y:", pPar->yres)
|
||||
GET_OPTION ("le:", pPar->left_margin)
|
||||
GET_OPTION ("ri:", pPar->right_margin)
|
||||
GET_OPTION ("up:", pPar->upper_margin)
|
||||
GET_OPTION ("lo:", pPar->lower_margin)
|
||||
GET_OPTION ("hs:", pPar->hsync_len)
|
||||
GET_OPTION ("vs:", pPar->vsync_len)
|
||||
GET_OPTION ("sync:", pPar->sync)
|
||||
GET_OPTION ("vmode:", pPar->vmode)
|
||||
GET_OPTION ("pclk:", pPar->pixclock)
|
||||
GET_OPTION ("depth:", bpp)
|
||||
p += i;
|
||||
if (*p != 0)
|
||||
p++; /* skip ',' */
|
||||
}
|
||||
return bpp;
|
||||
}
|
||||
|
||||
/*
|
||||
* Parse the 'video-mode' environment variable
|
||||
*
|
||||
* Example: "video-mode=fslfb:1280x1024-32@60,monitor=dvi". See
|
||||
* doc/README.video for more information on how to set the variable.
|
||||
*
|
||||
* @xres: returned value of X-resolution
|
||||
* @yres: returned value of Y-resolution
|
||||
* @depth: returned value of color depth
|
||||
* @freq: returned value of monitor frequency
|
||||
* @options: pointer to any remaining options, or NULL
|
||||
*
|
||||
* Returns 1 if valid values were found, 0 otherwise
|
||||
*/
|
||||
int video_get_video_mode(unsigned int *xres, unsigned int *yres,
|
||||
unsigned int *depth, unsigned int *freq, const char **options)
|
||||
{
|
||||
char *p = getenv("video-mode");
|
||||
if (!p)
|
||||
return 0;
|
||||
|
||||
/* Skip over the driver name, which we don't care about. */
|
||||
p = strchr(p, ':');
|
||||
if (!p)
|
||||
return 0;
|
||||
|
||||
/* Get the X-resolution*/
|
||||
while (*p && !isdigit(*p))
|
||||
p++;
|
||||
*xres = simple_strtoul(p, &p, 10);
|
||||
if (!*xres)
|
||||
return 0;
|
||||
|
||||
/* Get the Y-resolution */
|
||||
while (*p && !isdigit(*p))
|
||||
p++;
|
||||
*yres = simple_strtoul(p, &p, 10);
|
||||
if (!*yres)
|
||||
return 0;
|
||||
|
||||
/* Get the depth */
|
||||
while (*p && !isdigit(*p))
|
||||
p++;
|
||||
*depth = simple_strtoul(p, &p, 10);
|
||||
if (!*depth)
|
||||
return 0;
|
||||
|
||||
/* Get the frequency */
|
||||
while (*p && !isdigit(*p))
|
||||
p++;
|
||||
*freq = simple_strtoul(p, &p, 10);
|
||||
if (!*freq)
|
||||
return 0;
|
||||
|
||||
/* Find the extra options, if any */
|
||||
p = strchr(p, ',');
|
||||
*options = p ? p + 1 : NULL;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
|
@ -0,0 +1,91 @@
|
|||
/*
|
||||
* (C) Copyright 2004
|
||||
* Pierre Aubert, Staubli Faverges , <p.aubert@staubli.com>
|
||||
*
|
||||
* See file CREDITS for list of people who contributed to this
|
||||
* project.
|
||||
*
|
||||
* 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
|
||||
*/
|
||||
|
||||
|
||||
#ifndef CONFIG_SYS_DEFAULT_VIDEO_MODE
|
||||
#define CONFIG_SYS_DEFAULT_VIDEO_MODE 0x301
|
||||
#endif
|
||||
|
||||
/* Some mode definitions */
|
||||
#define FB_SYNC_HOR_HIGH_ACT 1 /* horizontal sync high active */
|
||||
#define FB_SYNC_VERT_HIGH_ACT 2 /* vertical sync high active */
|
||||
#define FB_SYNC_EXT 4 /* external sync */
|
||||
#define FB_SYNC_COMP_HIGH_ACT 8 /* composite sync high active */
|
||||
#define FB_SYNC_BROADCAST 16 /* broadcast video timings */
|
||||
/* vtotal = 144d/288n/576i => PAL */
|
||||
/* vtotal = 121d/242n/484i => NTSC */
|
||||
#define FB_SYNC_ON_GREEN 32 /* sync on green */
|
||||
#define FB_VMODE_NONINTERLACED 0 /* non interlaced */
|
||||
#define FB_VMODE_INTERLACED 1 /* interlaced */
|
||||
#define FB_VMODE_DOUBLE 2 /* double scan */
|
||||
#define FB_VMODE_MASK 255
|
||||
|
||||
#define FB_VMODE_YWRAP 256 /* ywrap instead of panning */
|
||||
#define FB_VMODE_SMOOTH_XPAN 512 /* smooth xpan possible (internally used) */
|
||||
#define FB_VMODE_CONUPDATE 512 /* don't update x/yoffset */
|
||||
|
||||
|
||||
/******************************************************************
|
||||
* Resolution Struct
|
||||
******************************************************************/
|
||||
struct ctfb_res_modes {
|
||||
int xres; /* visible resolution */
|
||||
int yres;
|
||||
/* Timing: All values in pixclocks, except pixclock (of course) */
|
||||
int pixclock; /* pixel clock in ps (pico seconds) */
|
||||
int left_margin; /* time from sync to picture */
|
||||
int right_margin; /* time from picture to sync */
|
||||
int upper_margin; /* time from sync to picture */
|
||||
int lower_margin;
|
||||
int hsync_len; /* length of horizontal sync */
|
||||
int vsync_len; /* length of vertical sync */
|
||||
int sync; /* see FB_SYNC_* */
|
||||
int vmode; /* see FB_VMODE_* */
|
||||
};
|
||||
|
||||
/******************************************************************
|
||||
* Vesa Mode Struct
|
||||
******************************************************************/
|
||||
struct ctfb_vesa_modes {
|
||||
int vesanr; /* Vesa number as in LILO (VESA Nr + 0x200} */
|
||||
int resindex; /* index to resolution struct */
|
||||
int bits_per_pixel; /* bpp */
|
||||
};
|
||||
|
||||
#define RES_MODE_640x480 0
|
||||
#define RES_MODE_800x600 1
|
||||
#define RES_MODE_1024x768 2
|
||||
#define RES_MODE_960_720 3
|
||||
#define RES_MODE_1152x864 4
|
||||
#define RES_MODE_1280x1024 5
|
||||
#define RES_MODES_COUNT 6
|
||||
|
||||
#define VESA_MODES_COUNT 19
|
||||
|
||||
extern const struct ctfb_vesa_modes vesa_modes[];
|
||||
extern const struct ctfb_res_modes res_mode_init[];
|
||||
|
||||
int video_get_params (struct ctfb_res_modes *pPar, char *penv);
|
||||
|
||||
int video_get_video_mode(unsigned int *xres, unsigned int *yres,
|
||||
unsigned int *depth, unsigned int *freq, const char **options);
|
||||
Loading…
Add table
Add a link
Reference in a new issue