pit: Create an exynos5420 directory which is nearly a copy of exynos5250.
This change creates an exynos5420 directory with code that will eventually implement support for the exynos5420 cpu from Samsung. Currently it's a copy of the exynos5250 directory with the name changed. There are going to be some problems where headers in src/cpu/samsung/exynos-common include headers in the exynos5250 directory directly. Change-Id: Ia8d7244310d32499238bbc171c0c668ec48178e1 Signed-off-by: Gabe Black <gabeblack@chromium.org> Reviewed-on: http://review.coreboot.org/3644 Tested-by: build bot (Jenkins) Reviewed-by: Stefan Reinauer <stefan.reinauer@coreboot.org>
This commit is contained in:
parent
dc006c1db4
commit
607c0b6d63
|
@ -1,4 +1,4 @@
|
|||
config CPU_SAMSUNG_EXYNOS5
|
||||
config CPU_SAMSUNG_EXYNOS5250
|
||||
depends on ARCH_ARMV7
|
||||
select HAVE_MONOTONIC_TIMER
|
||||
select HAVE_UART_SPECIAL
|
||||
|
@ -6,6 +6,18 @@ config CPU_SAMSUNG_EXYNOS5
|
|||
bool
|
||||
default n
|
||||
|
||||
if CPU_SAMSUNG_EXYNOS5
|
||||
config CPU_SAMSUNG_EXYNOS5420
|
||||
depends on ARCH_ARMV7
|
||||
select HAVE_MONOTONIC_TIMER
|
||||
select HAVE_UART_SPECIAL
|
||||
select DEFAULT_EARLY_CONSOLE
|
||||
bool
|
||||
default n
|
||||
|
||||
if CPU_SAMSUNG_EXYNOS5250
|
||||
source src/cpu/samsung/exynos5250/Kconfig
|
||||
endif
|
||||
|
||||
if CPU_SAMSUNG_EXYNOS5420
|
||||
source src/cpu/samsung/exynos5420/Kconfig
|
||||
endif
|
||||
|
|
|
@ -1 +1,2 @@
|
|||
subdirs-$(CONFIG_CPU_SAMSUNG_EXYNOS5) += exynos5250
|
||||
subdirs-$(CONFIG_CPU_SAMSUNG_EXYNOS5250) += exynos5250
|
||||
subdirs-$(CONFIG_CPU_SAMSUNG_EXYNOS5420) += exynos5420
|
||||
|
|
|
@ -0,0 +1,133 @@
|
|||
config BOOTBLOCK_CPU_INIT
|
||||
string
|
||||
default "cpu/samsung/exynos5420/bootblock.c"
|
||||
help
|
||||
CPU/SoC-specific bootblock code. This is useful if the
|
||||
bootblock must load microcode or copy data from ROM before
|
||||
searching for the bootblock.
|
||||
|
||||
config EXYNOS_ACE_SHA
|
||||
bool
|
||||
default n
|
||||
|
||||
config BL1_SIZE_KB
|
||||
int
|
||||
default 8
|
||||
|
||||
# Example SRAM/iRAM map for Exynos5420 platform:
|
||||
#
|
||||
# 0x0202_0000: vendor-provided BL1
|
||||
# 0x0202_3400: bootblock, assume up to 32KB in size
|
||||
# 0x0203_0000: romstage, assume up to 128KB in size.
|
||||
# 0x0207_8000: stack pointer
|
||||
|
||||
config BOOTBLOCK_BASE
|
||||
hex
|
||||
default 0x02023400
|
||||
|
||||
config ROMSTAGE_BASE
|
||||
hex
|
||||
default 0x02030000
|
||||
|
||||
config ROMSTAGE_SIZE
|
||||
hex
|
||||
default 0x10000
|
||||
|
||||
# Stack may reside in either IRAM or DRAM. We will define it to live
|
||||
# at the top of IRAM for now.
|
||||
#
|
||||
# Stack grows downward, push operation stores register contents in
|
||||
# consecutive memory locations ending just below SP
|
||||
config STACK_TOP
|
||||
hex
|
||||
default 0x02078000
|
||||
|
||||
config STACK_BOTTOM
|
||||
hex
|
||||
default 0x02077000
|
||||
|
||||
config STACK_SIZE
|
||||
hex
|
||||
default 0x1000
|
||||
|
||||
config CBFS_ROM_OFFSET
|
||||
# Calculated by BL1 + max bootblock size.
|
||||
hex "offset of CBFS data in ROM"
|
||||
default 0x0A000
|
||||
|
||||
# TODO Change this to some better address not overlapping bootblock when
|
||||
# cbfstool supports creating header in arbitrary location.
|
||||
config CBFS_HEADER_ROM_OFFSET
|
||||
hex "offset of master CBFS header in ROM"
|
||||
default 0x2040
|
||||
|
||||
# TODO We may probably move this to board-specific implementation files instead
|
||||
# of KConfig values.
|
||||
config CBFS_CACHE_ADDRESS
|
||||
hex "memory address to put CBFS cache data"
|
||||
default 0x02060000
|
||||
|
||||
config CBFS_CACHE_SIZE
|
||||
hex "size of CBFS cache data"
|
||||
default 0x000017000
|
||||
|
||||
# FIXME: This is for copying SPI content into SRAM temporarily and
|
||||
# will be removed when we have the SPI streaming driver implemented.
|
||||
config SPI_IMAGE_HACK
|
||||
hex
|
||||
default 0x02060000
|
||||
|
||||
# FIXME: other magic numbers that should probably go away
|
||||
config XIP_ROM_SIZE
|
||||
hex
|
||||
default ROMSTAGE_SIZE
|
||||
|
||||
config SYS_SDRAM_BASE
|
||||
hex
|
||||
default 0x40000000
|
||||
|
||||
config SYS_TEXT_BASE
|
||||
hex
|
||||
default 0x43e00000
|
||||
|
||||
config COREBOOT_TABLES_SIZE
|
||||
hex
|
||||
default 0x4000000
|
||||
|
||||
choice CONSOLE_SERIAL_UART_CHOICES
|
||||
prompt "Serial Console UART"
|
||||
default CONSOLE_SERIAL_UART3
|
||||
depends on CONSOLE_SERIAL_UART
|
||||
|
||||
config CONSOLE_SERIAL_UART0
|
||||
bool "UART0"
|
||||
help
|
||||
Serial console on UART0
|
||||
|
||||
config CONSOLE_SERIAL_UART1
|
||||
bool "UART1"
|
||||
help
|
||||
Serial console on UART1
|
||||
|
||||
config CONSOLE_SERIAL_UART2
|
||||
bool "UART2"
|
||||
help
|
||||
Serial console on UART2
|
||||
|
||||
config CONSOLE_SERIAL_UART3
|
||||
bool "UART3"
|
||||
help
|
||||
Serial console on UART3
|
||||
|
||||
endchoice
|
||||
|
||||
config CONSOLE_SERIAL_UART_ADDRESS
|
||||
hex
|
||||
depends on CONSOLE_SERIAL_UART
|
||||
default 0x12c00000 if CONSOLE_SERIAL_UART0
|
||||
default 0x12c10000 if CONSOLE_SERIAL_UART1
|
||||
default 0x12c20000 if CONSOLE_SERIAL_UART2
|
||||
default 0x12c30000 if CONSOLE_SERIAL_UART3
|
||||
help
|
||||
Map the UART names to the respective MMIO address.
|
||||
|
|
@ -0,0 +1,55 @@
|
|||
# Run an intermediate step when producing coreboot.rom
|
||||
# that adds additional components to the final firmware
|
||||
# image outside of CBFS
|
||||
INTERMEDIATE += exynos5420_add_bl1
|
||||
|
||||
bootblock-y += spi.c
|
||||
bootblock-y += pinmux.c mct.c power.c
|
||||
# Clock is required for UART
|
||||
bootblock-$(CONFIG_EARLY_CONSOLE) += clock_init.c
|
||||
bootblock-$(CONFIG_EARLY_CONSOLE) += clock.c
|
||||
bootblock-$(CONFIG_EARLY_CONSOLE) += monotonic_timer.c
|
||||
bootblock-$(CONFIG_EARLY_CONSOLE) += uart.c
|
||||
bootblock-y += wakeup.c
|
||||
bootblock-y += gpio.c
|
||||
bootblock-$(CONFIG_EARLY_CONSOLE) += pwm.c
|
||||
bootblock-$(CONFIG_EARLY_CONSOLE) += timer.c
|
||||
|
||||
romstage-y += spi.c
|
||||
romstage-y += clock.c
|
||||
romstage-y += clock_init.c
|
||||
romstage-y += pinmux.c # required by s3c24x0_i2c and uart.
|
||||
romstage-y += dmc_common.c
|
||||
romstage-y += dmc_init_ddr3.c
|
||||
romstage-y += power.c
|
||||
romstage-y += mct.c
|
||||
romstage-y += monotonic_timer.c
|
||||
romstage-$(CONFIG_EARLY_CONSOLE) += uart.c
|
||||
romstage-y += wakeup.c
|
||||
romstage-y += pwm.c # needed by timer.c
|
||||
romstage-y += gpio.c
|
||||
romstage-y += timer.c
|
||||
romstage-y += i2c.c
|
||||
#romstage-y += wdt.c
|
||||
|
||||
ramstage-y += spi.c
|
||||
ramstage-y += clock.c
|
||||
ramstage-y += clock_init.c
|
||||
ramstage-y += pinmux.c
|
||||
ramstage-y += power.c
|
||||
ramstage-$(CONFIG_CONSOLE_SERIAL_UART) += uart.c
|
||||
ramstage-y += cpu.c
|
||||
ramstage-y += tmu.c
|
||||
ramstage-y += mct.c
|
||||
ramstage-y += monotonic_timer.c
|
||||
ramstage-y += pwm.c # needed by timer.c
|
||||
ramstage-y += timer.c
|
||||
ramstage-y += gpio.c
|
||||
ramstage-y += i2c.c
|
||||
ramstage-y += dp-reg.c
|
||||
ramstage-y += fb.c
|
||||
|
||||
exynos5420_add_bl1: $(obj)/coreboot.pre
|
||||
printf " DD Adding Samsung Exynos5420 BL1\n"
|
||||
dd if=3rdparty/cpu/samsung/exynos5420/bl1.bin \
|
||||
of=$(obj)/coreboot.pre conv=notrunc >/dev/null 2>&1
|
|
@ -0,0 +1,43 @@
|
|||
/*
|
||||
* This file is part of the coreboot project.
|
||||
*
|
||||
* Copyright 2013 Google Inc.
|
||||
*
|
||||
* 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; version 2 of 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include <console/console.h>
|
||||
#include "clk.h"
|
||||
#include "wakeup.h"
|
||||
|
||||
void bootblock_cpu_init(void);
|
||||
void bootblock_cpu_init(void)
|
||||
{
|
||||
/* kick off the multi-core timer.
|
||||
* We want to do this as early as we can.
|
||||
*/
|
||||
mct_start();
|
||||
|
||||
if (get_wakeup_state() == WAKEUP_DIRECT) {
|
||||
wakeup();
|
||||
/* Never returns. */
|
||||
}
|
||||
|
||||
/* For most ARM systems, we have to initialize firmware media source
|
||||
* (ex, SPI, SD/MMC, or eMMC) now; but for Exynos platform, that is
|
||||
* already handled by iROM so there's no need to setup again.
|
||||
*/
|
||||
|
||||
console_init();
|
||||
}
|
|
@ -0,0 +1,40 @@
|
|||
/*
|
||||
* This file is part of the coreboot project.
|
||||
*
|
||||
* Copyright 2013 Google Inc.
|
||||
*
|
||||
* 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; version 2 of 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#ifndef CPU_SAMSUNG_EXYNOS5420_H
|
||||
#define CPU_SAMSUNG_EXYNOS5420_H
|
||||
|
||||
struct cpu_samsung_exynos5420_config {
|
||||
/* special magic numbers! */
|
||||
int clkval_f;
|
||||
int upper_margin;
|
||||
int lower_margin;
|
||||
int vsync;
|
||||
int left_margin;
|
||||
int right_margin;
|
||||
int hsync;
|
||||
|
||||
int xres;
|
||||
int yres;
|
||||
int bpp;
|
||||
|
||||
u32 lcdbase;
|
||||
};
|
||||
|
||||
#endif /* CPU_SAMSUNG_EXYNOS5420_H */
|
|
@ -0,0 +1,624 @@
|
|||
/*
|
||||
* This file is part of the coreboot project.
|
||||
*
|
||||
* Copyright 2013 Google Inc.
|
||||
* Copyright (C) 2012 Samsung Electronics
|
||||
*
|
||||
* 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; version 2 of 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#ifndef CPU_SAMSUNG_EXYNOS5420_CLK_H
|
||||
#define CPU_SAMSUNG_EXYNOS5420_CLK_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
enum periph_id;
|
||||
|
||||
#define APLL 0
|
||||
#define MPLL 1
|
||||
#define EPLL 2
|
||||
#define HPLL 3
|
||||
#define VPLL 4
|
||||
#define BPLL 5
|
||||
|
||||
enum pll_src_bit {
|
||||
SRC_MPLL = 6,
|
||||
SRC_EPLL,
|
||||
SRC_VPLL,
|
||||
};
|
||||
|
||||
/* *
|
||||
* This structure is to store the src bit, div bit and prediv bit
|
||||
* positions of the peripheral clocks of the src and div registers
|
||||
*/
|
||||
struct clk_bit_info {
|
||||
s8 src_bit; /* offset in register to clock source field */
|
||||
s8 n_src_bits; /* number of bits in 'src_bit' field */
|
||||
s8 div_bit;
|
||||
s8 prediv_bit;
|
||||
};
|
||||
|
||||
unsigned long get_pll_clk(int pllreg);
|
||||
unsigned long get_arm_clk(void);
|
||||
unsigned long get_pwm_clk(void);
|
||||
unsigned long get_uart_clk(int dev_index);
|
||||
void set_mmc_clk(int dev_index, unsigned int div);
|
||||
|
||||
/**
|
||||
* get the clk frequency of the required peripherial
|
||||
*
|
||||
* @param peripherial Peripherial id
|
||||
*
|
||||
* @return frequency of the peripherial clk
|
||||
*/
|
||||
unsigned long clock_get_periph_rate(enum periph_id peripheral);
|
||||
|
||||
#include "pinmux.h"
|
||||
|
||||
|
||||
#define MCT_ADDRESS 0x101c0000
|
||||
|
||||
#define MCT_HZ 24000000
|
||||
|
||||
/*
|
||||
* Set mshci controller instances clock drivder
|
||||
*
|
||||
* @param enum periph_id instance of the mshci controller
|
||||
*
|
||||
* Return 0 if ok else -1
|
||||
*/
|
||||
int clock_set_mshci(enum periph_id peripheral);
|
||||
|
||||
/*
|
||||
* Sets the epll clockrate
|
||||
*
|
||||
* @param rate Required clock rate to the presacaler in Hz
|
||||
*
|
||||
* Return 0 if ok else -1
|
||||
*/
|
||||
int clock_epll_set_rate(unsigned long rate);
|
||||
|
||||
/*
|
||||
* selects the clk source for I2S MCLK
|
||||
*/
|
||||
void clock_select_i2s_clk_source(void);
|
||||
|
||||
/*
|
||||
* Set prescaler division based on input and output frequency
|
||||
* for i2s audio clock
|
||||
*
|
||||
* @param src_frq Source frequency in Hz
|
||||
* @param dst_frq Required MCLK frequency in Hz
|
||||
*
|
||||
* Return 0 if ok else -1
|
||||
*/
|
||||
int clock_set_i2s_clk_prescaler(unsigned int src_frq, unsigned int dst_frq);
|
||||
|
||||
struct exynos5_clock {
|
||||
unsigned int apll_lock; /* base + 0 */
|
||||
unsigned char res1[0xfc];
|
||||
unsigned int apll_con0;
|
||||
unsigned int apll_con1;
|
||||
unsigned char res2[0xf8];
|
||||
unsigned int src_cpu;
|
||||
unsigned char res3[0x1fc];
|
||||
unsigned int mux_stat_cpu;
|
||||
unsigned char res4[0xfc];
|
||||
unsigned int div_cpu0;
|
||||
unsigned int div_cpu1;
|
||||
unsigned char res5[0xf8];
|
||||
unsigned int div_stat_cpu0;
|
||||
unsigned int div_stat_cpu1;
|
||||
unsigned char res6[0x1f8];
|
||||
unsigned int gate_sclk_cpu;
|
||||
unsigned char res7[0x1fc];
|
||||
unsigned int clkout_cmu_cpu;
|
||||
unsigned int clkout_cmu_cpu_div_stat;
|
||||
unsigned char res8[0x5f8];
|
||||
|
||||
unsigned int armclk_stopctrl; /* base + 0x1000 */
|
||||
unsigned int atclk_stopctrl;
|
||||
unsigned char res9[0x8];
|
||||
unsigned int parityfail_status;
|
||||
unsigned int parityfail_clear;
|
||||
unsigned char res10[0x8];
|
||||
unsigned int pwr_ctrl;
|
||||
unsigned int pwr_ctr2;
|
||||
unsigned char res11[0xd8];
|
||||
unsigned int apll_con0_l8;
|
||||
unsigned int apll_con0_l7;
|
||||
unsigned int apll_con0_l6;
|
||||
unsigned int apll_con0_l5;
|
||||
unsigned int apll_con0_l4;
|
||||
unsigned int apll_con0_l3;
|
||||
unsigned int apll_con0_l2;
|
||||
unsigned int apll_con0_l1;
|
||||
unsigned int iem_control;
|
||||
unsigned char res12[0xdc];
|
||||
unsigned int apll_con1_l8;
|
||||
unsigned int apll_con1_l7;
|
||||
unsigned int apll_con1_l6;
|
||||
unsigned int apll_con1_l5;
|
||||
unsigned int apll_con1_l4;
|
||||
unsigned int apll_con1_l3;
|
||||
unsigned int apll_con1_l2;
|
||||
unsigned int apll_con1_l1;
|
||||
unsigned char res13[0xe0];
|
||||
unsigned int div_iem_l8;
|
||||
unsigned int div_iem_l7;
|
||||
unsigned int div_iem_l6;
|
||||
unsigned int div_iem_l5;
|
||||
unsigned int div_iem_l4;
|
||||
unsigned int div_iem_l3;
|
||||
unsigned int div_iem_l2;
|
||||
unsigned int div_iem_l1;
|
||||
unsigned char res14[0x2ce0];
|
||||
|
||||
unsigned int mpll_lock; /* base + 0x4000 */
|
||||
unsigned char res15[0xfc];
|
||||
unsigned int mpll_con0;
|
||||
unsigned int mpll_con1;
|
||||
unsigned char res16[0xf8];
|
||||
unsigned int src_core0;
|
||||
unsigned int src_core1;
|
||||
unsigned char res17[0xf8];
|
||||
unsigned int src_mask_core;
|
||||
unsigned char res18[0x100];
|
||||
unsigned int mux_stat_core1;
|
||||
unsigned char res19[0xf8];
|
||||
unsigned int div_core0;
|
||||
unsigned int div_core1;
|
||||
unsigned int div_sysrgt;
|
||||
unsigned char res20[0xf4];
|
||||
unsigned int div_stat_core0;
|
||||
unsigned int div_stat_core1;
|
||||
unsigned int div_stat_sysrgt;
|
||||
unsigned char res21[0x2f4];
|
||||
unsigned int gate_ip_core;
|
||||
unsigned int gate_ip_sysrgt;
|
||||
unsigned char res22[0xf8];
|
||||
unsigned int clkout_cmu_core;
|
||||
unsigned int clkout_cmu_core_div_stat;
|
||||
unsigned char res23[0x5f8];
|
||||
|
||||
unsigned int dcgidx_map0; /* base + 0x5000 */
|
||||
unsigned int dcgidx_map1;
|
||||
unsigned int dcgidx_map2;
|
||||
unsigned char res24[0x14];
|
||||
unsigned int dcgperf_map0;
|
||||
unsigned int dcgperf_map1;
|
||||
unsigned char res25[0x18];
|
||||
unsigned int dvcidx_map;
|
||||
unsigned char res26[0x1c];
|
||||
unsigned int freq_cpu;
|
||||
unsigned int freq_dpm;
|
||||
unsigned char res27[0x18];
|
||||
unsigned int dvsemclk_en;
|
||||
unsigned int maxperf;
|
||||
unsigned char res28[0x3478];
|
||||
|
||||
unsigned int div_acp; /* base + 0x8500 */
|
||||
unsigned char res29[0xfc];
|
||||
unsigned int div_stat_acp;
|
||||
unsigned char res30[0x1fc];
|
||||
unsigned int gate_ip_acp;
|
||||
unsigned char res31a[0xfc];
|
||||
unsigned int div_syslft;
|
||||
unsigned char res31b[0xc];
|
||||
unsigned int div_stat_syslft;
|
||||
unsigned char res31c[0xc];
|
||||
unsigned int gate_bus_syslft;
|
||||
unsigned char res31d[0xdc];
|
||||
unsigned int clkout_cmu_acp;
|
||||
unsigned int clkout_cmu_acp_div_stat;
|
||||
unsigned char res32[0x38f8];
|
||||
|
||||
unsigned int div_isp0; /* base + 0xc300 */
|
||||
unsigned int div_isp1;
|
||||
unsigned int div_isp2;
|
||||
unsigned char res33[0xf4];
|
||||
|
||||
unsigned int div_stat_isp0; /* base + 0xc400 */
|
||||
unsigned int div_stat_isp1;
|
||||
unsigned int div_stat_isp2;
|
||||
unsigned char res34[0x3f4];
|
||||
|
||||
unsigned int gate_ip_isp0; /* base + 0xc800 */
|
||||
unsigned int gate_ip_isp1;
|
||||
unsigned char res35[0xf8];
|
||||
unsigned int gate_sclk_isp;
|
||||
unsigned char res36[0xc];
|
||||
unsigned int mcuisp_pwr_ctrl;
|
||||
unsigned char res37[0xec];
|
||||
unsigned int clkout_cmu_isp;
|
||||
unsigned int clkout_cmu_isp_div_stat;
|
||||
unsigned char res38[0x3618];
|
||||
|
||||
unsigned int cpll_lock; /* base + 0x10020 */
|
||||
unsigned char res39[0xc];
|
||||
unsigned int epll_lock;
|
||||
unsigned char res40[0xc];
|
||||
unsigned int vpll_lock;
|
||||
unsigned char res41a[0xc];
|
||||
unsigned int gpll_lock;
|
||||
unsigned char res41b[0xcc];
|
||||
unsigned int cpll_con0;
|
||||
unsigned int cpll_con1;
|
||||
unsigned char res42[0x8];
|
||||
unsigned int epll_con0;
|
||||
unsigned int epll_con1;
|
||||
unsigned int epll_con2;
|
||||
unsigned char res43[0x4];
|
||||
unsigned int vpll_con0;
|
||||
unsigned int vpll_con1;
|
||||
unsigned int vpll_con2;
|
||||
unsigned char res44a[0x4];
|
||||
unsigned int gpll_con0;
|
||||
unsigned int gpll_con1;
|
||||
unsigned char res44b[0xb8];
|
||||
unsigned int src_top0;
|
||||
unsigned int src_top1;
|
||||
unsigned int src_top2;
|
||||
unsigned int src_top3;
|
||||
unsigned int src_gscl;
|
||||
unsigned int src_disp0_0;
|
||||
unsigned int src_disp0_1;
|
||||
unsigned int src_disp1_0;
|
||||
unsigned int src_disp1_1;
|
||||
unsigned char res46[0xc];
|
||||
unsigned int src_mau;
|
||||
unsigned int src_fsys;
|
||||
unsigned char res47[0x8];
|
||||
unsigned int src_peric0;
|
||||
unsigned int src_peric1;
|
||||
unsigned char res48[0x18];
|
||||
unsigned int sclk_src_isp;
|
||||
unsigned char res49[0x9c];
|
||||
unsigned int src_mask_top;
|
||||
unsigned char res50[0xc];
|
||||
unsigned int src_mask_gscl;
|
||||
unsigned int src_mask_disp0_0;
|
||||
unsigned int src_mask_disp0_1;
|
||||
unsigned int src_mask_disp1_0;
|
||||
unsigned int src_mask_disp1_1;
|
||||
unsigned int src_mask_maudio;
|
||||
unsigned char res52[0x8];
|
||||
unsigned int src_mask_fsys;
|
||||
unsigned char res53[0xc];
|
||||
unsigned int src_mask_peric0;
|
||||
unsigned int src_mask_peric1;
|
||||
unsigned char res54[0x18];
|
||||
unsigned int src_mask_isp;
|
||||
unsigned char res55[0x9c];
|
||||
unsigned int mux_stat_top0;
|
||||
unsigned int mux_stat_top1;
|
||||
unsigned int mux_stat_top2;
|
||||
unsigned int mux_stat_top3;
|
||||
unsigned char res56[0xf0];
|
||||
unsigned int div_top0;
|
||||
unsigned int div_top1;
|
||||
unsigned char res57[0x8];
|
||||
unsigned int div_gscl;
|
||||
unsigned int div_disp0_0;
|
||||
unsigned int div_disp0_1;
|
||||
unsigned int div_disp1_0;
|
||||
unsigned int div_disp1_1;
|
||||
unsigned char res59[0x8];
|
||||
unsigned int div_gen;
|
||||
unsigned char res60[0x4];
|
||||
unsigned int div_mau;
|
||||
unsigned int div_fsys0;
|
||||
unsigned int div_fsys1;
|
||||
unsigned int div_fsys2;
|
||||
unsigned int div_fsys3;
|
||||
unsigned int div_peric0;
|
||||
unsigned int div_peric1;
|
||||
unsigned int div_peric2;
|
||||
unsigned int div_peric3;
|
||||
unsigned int div_peric4;
|
||||
unsigned int div_peric5;
|
||||
unsigned char res61[0x10];
|
||||
unsigned int sclk_div_isp;
|
||||
unsigned char res62[0xc];
|
||||
unsigned int div2_ratio0;
|
||||
unsigned int div2_ratio1;
|
||||
unsigned char res63[0x8];
|
||||
unsigned int div4_ratio;
|
||||
unsigned char res64[0x6c];
|
||||
unsigned int div_stat_top0;
|
||||
unsigned int div_stat_top1;
|
||||
unsigned char res65[0x8];
|
||||
unsigned int div_stat_gscl;
|
||||
unsigned int div_stat_disp0_0;
|
||||
unsigned int div_stat_disp0_1;
|
||||
unsigned int div_stat_disp1_0;
|
||||
unsigned int div_stat_disp1_1;
|
||||
unsigned char res67[0x8];
|
||||
unsigned int div_stat_gen;
|
||||
unsigned char res68[0x4];
|
||||
unsigned int div_stat_maudio;
|
||||
unsigned int div_stat_fsys0;
|
||||
unsigned int div_stat_fsys1;
|
||||
unsigned int div_stat_fsys2;
|
||||
unsigned int div_stat_fsys3;
|
||||
unsigned int div_stat_peric0;
|
||||
unsigned int div_stat_peric1;
|
||||
unsigned int div_stat_peric2;
|
||||
unsigned int div_stat_peric3;
|
||||
unsigned int div_stat_peric4;
|
||||
unsigned int div_stat_peric5;
|
||||
unsigned char res69[0x10];
|
||||
unsigned int sclk_div_stat_isp;
|
||||
unsigned char res70[0xc];
|
||||
unsigned int div2_stat0;
|
||||
unsigned int div2_stat1;
|
||||
unsigned char res71[0x8];
|
||||
unsigned int div4_stat;
|
||||
unsigned char res72[0x180];
|
||||
unsigned int gate_top_sclk_disp0;
|
||||
unsigned int gate_top_sclk_disp1;
|
||||
unsigned int gate_top_sclk_gen;
|
||||
unsigned char res74[0xc];
|
||||
unsigned int gate_top_sclk_mau;
|
||||
unsigned int gate_top_sclk_fsys;
|
||||
unsigned char res75[0xc];
|
||||
unsigned int gate_top_sclk_peric;
|
||||
unsigned char res76[0x1c];
|
||||
unsigned int gate_top_sclk_isp;
|
||||
unsigned char res77[0xac];
|
||||
unsigned int gate_ip_gscl;
|
||||
unsigned int gate_ip_disp0;
|
||||
unsigned int gate_ip_disp1;
|
||||
unsigned int gate_ip_mfc;
|
||||
unsigned int gate_ip_g3d;
|
||||
unsigned int gate_ip_gen;
|
||||
unsigned char res79[0xc];
|
||||
unsigned int gate_ip_fsys;
|
||||
unsigned char res80[0x4];
|
||||
unsigned int gate_ip_gps;
|
||||
unsigned int gate_ip_peric;
|
||||
unsigned char res81[0xc];
|
||||
unsigned int gate_ip_peris;
|
||||
unsigned char res82[0x1c];
|
||||
unsigned int gate_block;
|
||||
unsigned char res83[0x7c];
|
||||
unsigned int clkout_cmu_top;
|
||||
unsigned int clkout_cmu_top_div_stat;
|
||||
unsigned char res84[0x37f8];
|
||||
|
||||
unsigned int src_lex; /* base + 0x14200 */
|
||||
unsigned char res85[0x1fc];
|
||||
unsigned int mux_stat_lex;
|
||||
unsigned char res85b[0xfc];
|
||||
unsigned int div_lex;
|
||||
unsigned char res86[0xfc];
|
||||
unsigned int div_stat_lex;
|
||||
unsigned char res87[0x1fc];
|
||||
unsigned int gate_ip_lex;
|
||||
unsigned char res88[0x1fc];
|
||||
unsigned int clkout_cmu_lex;
|
||||
unsigned int clkout_cmu_lex_div_stat;
|
||||
unsigned char res89[0x3af8];
|
||||
|
||||
unsigned int div_r0x; /* base + 0x18500 */
|
||||
unsigned char res90[0xfc];
|
||||
unsigned int div_stat_r0x;
|
||||
unsigned char res91[0x1fc];
|
||||
unsigned int gate_ip_r0x;
|
||||
unsigned char res92[0x1fc];
|
||||
unsigned int clkout_cmu_r0x;
|
||||
unsigned int clkout_cmu_r0x_div_stat;
|
||||
unsigned char res94[0x3af8];
|
||||
|
||||
unsigned int div_r1x; /* base + 0x1c500 */
|
||||
unsigned char res95[0xfc];
|
||||
unsigned int div_stat_r1x;
|
||||
unsigned char res96[0x1fc];
|
||||
unsigned int gate_ip_r1x;
|
||||
unsigned char res97[0x1fc];
|
||||
unsigned int clkout_cmu_r1x;
|
||||
unsigned int clkout_cmu_r1x_div_stat;
|
||||
unsigned char res98[0x3608];
|
||||
|
||||
unsigned int bpll_lock; /* base + 0x2000c */
|
||||
unsigned char res99[0xfc];
|
||||
unsigned int bpll_con0;
|
||||
unsigned int bpll_con1;
|
||||
unsigned char res100[0xe8];
|
||||
unsigned int src_cdrex;
|
||||
unsigned char res101[0x1fc];
|
||||
unsigned int mux_stat_cdrex;
|
||||
unsigned char res102[0xfc];
|
||||
unsigned int div_cdrex;
|
||||
unsigned int div_cdrex2;
|
||||
unsigned char res103[0xf8];
|
||||
unsigned int div_stat_cdrex;
|
||||
unsigned char res104[0x2fc];
|
||||
unsigned int gate_ip_cdrex;
|
||||
unsigned char res105[0xc];
|
||||
unsigned int c2c_monitor;
|
||||
unsigned int dmc_pwr_ctrl;
|
||||
unsigned char res106[0x4];
|
||||
unsigned int drex2_pause;
|
||||
unsigned char res107[0xe0];
|
||||
unsigned int clkout_cmu_cdrex;
|
||||
unsigned int clkout_cmu_cdrex_div_stat;
|
||||
unsigned char res108[0x8];
|
||||
unsigned int lpddr3phy_ctrl;
|
||||
unsigned char res109a[0xc];
|
||||
unsigned int lpddr3phy_con3;
|
||||
unsigned int pll_div2_sel;
|
||||
unsigned char res109b[0xf5e4];
|
||||
};
|
||||
|
||||
struct exynos5_mct_regs {
|
||||
uint32_t mct_cfg;
|
||||
uint8_t reserved0[0xfc];
|
||||
uint32_t g_cnt_l;
|
||||
uint32_t g_cnt_u;
|
||||
uint8_t reserved1[0x8];
|
||||
uint32_t g_cnt_wstat;
|
||||
uint8_t reserved2[0xec];
|
||||
uint32_t g_comp0_l;
|
||||
uint32_t g_comp0_u;
|
||||
uint32_t g_comp0_addr_incr;
|
||||
uint8_t reserved3[0x4];
|
||||
uint32_t g_comp1_l;
|
||||
uint32_t g_comp1_u;
|
||||
uint32_t g_comp1_addr_incr;
|
||||
uint8_t reserved4[0x4];
|
||||
uint32_t g_comp2_l;
|
||||
uint32_t g_comp2_u;
|
||||
uint32_t g_comp2_addr_incr;
|
||||
uint8_t reserved5[0x4];
|
||||
uint32_t g_comp3_l;
|
||||
uint32_t g_comp3_u;
|
||||
uint32_t g_comp3_addr_incr;
|
||||
uint8_t reserved6[0x4];
|
||||
uint32_t g_tcon;
|
||||
uint32_t g_int_cstat;
|
||||
uint32_t g_int_enb;
|
||||
uint32_t g_wstat;
|
||||
uint8_t reserved7[0xb0];
|
||||
uint32_t l0_tcntb;
|
||||
uint32_t l0_tcnto;
|
||||
uint32_t l0_icntb;
|
||||
uint32_t l0_icnto;
|
||||
uint32_t l0_frcntb;
|
||||
uint32_t l0_frcnto;
|
||||
uint8_t reserved8[0x8];
|
||||
uint32_t l0_tcon;
|
||||
uint8_t reserved9[0xc];
|
||||
uint32_t l0_int_cstat;
|
||||
uint32_t l0_int_enb;
|
||||
uint8_t reserved10[0x8];
|
||||
uint32_t l0_wstat;
|
||||
uint8_t reserved11[0xbc];
|
||||
uint32_t l1_tcntb;
|
||||
uint32_t l1_tcnto;
|
||||
uint32_t l1_icntb;
|
||||
uint32_t l1_icnto;
|
||||
uint32_t l1_frcntb;
|
||||
uint32_t l1_frcnto;
|
||||
uint8_t reserved12[0x8];
|
||||
uint32_t l1_tcon;
|
||||
uint8_t reserved13[0xc];
|
||||
uint32_t l1_int_cstat;
|
||||
uint32_t l1_int_enb;
|
||||
uint8_t reserved14[0x8];
|
||||
uint32_t l1_wstat;
|
||||
};
|
||||
|
||||
#define EXYNOS5_EPLLCON0_LOCKED_SHIFT 29 /* EPLL Locked bit position*/
|
||||
#define EPLL_SRC_CLOCK 24000000 /*24 MHz Cristal Input */
|
||||
#define TIMEOUT_EPLL_LOCK 1000
|
||||
|
||||
#define AUDIO_0_RATIO_MASK 0x0f
|
||||
#define AUDIO_1_RATIO_MASK 0x0f
|
||||
|
||||
#define CLK_SRC_PERIC1 0x254
|
||||
#define AUDIO1_SEL_MASK 0xf
|
||||
#define CLK_SRC_AUDIOCDCLK1 0x0
|
||||
#define CLK_SRC_XXTI 0x1
|
||||
#define CLK_SRC_SCLK_EPLL 0x7
|
||||
|
||||
/* CON0 bit-fields */
|
||||
#define EPLL_CON0_MDIV_MASK 0x1ff
|
||||
#define EPLL_CON0_PDIV_MASK 0x3f
|
||||
#define EPLL_CON0_SDIV_MASK 0x7
|
||||
#define EPLL_CON0_LOCKED_SHIFT 29
|
||||
#define EPLL_CON0_MDIV_SHIFT 16
|
||||
#define EPLL_CON0_PDIV_SHIFT 8
|
||||
#define EPLL_CON0_SDIV_SHIFT 0
|
||||
#define EPLL_CON0_LOCK_DET_EN_SHIFT 28
|
||||
#define EPLL_CON0_LOCK_DET_EN_MASK 1
|
||||
|
||||
/* structure for epll configuration used in audio clock configuration */
|
||||
struct st_epll_con_val {
|
||||
unsigned int freq_out; /* frequency out */
|
||||
unsigned int en_lock_det; /* enable lock detect */
|
||||
unsigned int m_div; /* m divider value */
|
||||
unsigned int p_div; /* p divider value */
|
||||
unsigned int s_div; /* s divider value */
|
||||
unsigned int k_dsm; /* k value of delta signal modulator */
|
||||
};
|
||||
|
||||
/**
|
||||
* Low-level function to set the clock pre-ratio for a peripheral
|
||||
*
|
||||
* @param periph_id Peripheral ID of peripheral to change
|
||||
* @param divisor New divisor for this peripheral's clock
|
||||
*/
|
||||
void clock_ll_set_pre_ratio(enum periph_id periph_id, unsigned divisor);
|
||||
|
||||
/**
|
||||
* Low-level function to set the clock ratio for a peripheral
|
||||
*
|
||||
* @param periph_id Peripheral ID of peripheral to change
|
||||
* @param divisor New divisor for this peripheral's clock
|
||||
*/
|
||||
void clock_ll_set_ratio(enum periph_id periph_id, unsigned divisor);
|
||||
|
||||
/**
|
||||
* Low-level function that selects the best clock scalars for a given rate and
|
||||
* sets up the given peripheral's clock accordingly.
|
||||
*
|
||||
* @param periph_id Peripheral ID of peripheral to change
|
||||
* @param rate Desired clock rate in Hz
|
||||
*
|
||||
* @return zero on success, negative on error
|
||||
*/
|
||||
int clock_set_rate(enum periph_id periph_id, unsigned int rate);
|
||||
|
||||
/* Clock gate unused IP */
|
||||
void clock_gate(void);
|
||||
|
||||
void mct_start(void);
|
||||
uint64_t mct_raw_value(void);
|
||||
|
||||
#include "dmc.h"
|
||||
|
||||
/* These are the ratio's for configuring ARM clock */
|
||||
struct arm_clk_ratios {
|
||||
unsigned int arm_freq_mhz; /* Frequency of ARM core in MHz */
|
||||
|
||||
unsigned int apll_mdiv;
|
||||
unsigned int apll_pdiv;
|
||||
unsigned int apll_sdiv;
|
||||
|
||||
unsigned int arm2_ratio;
|
||||
unsigned int apll_ratio;
|
||||
unsigned int pclk_dbg_ratio;
|
||||
unsigned int atb_ratio;
|
||||
unsigned int periph_ratio;
|
||||
unsigned int acp_ratio;
|
||||
unsigned int cpud_ratio;
|
||||
unsigned int arm_ratio;
|
||||
};
|
||||
|
||||
/**
|
||||
* Get the clock ratios for CPU configuration
|
||||
*
|
||||
* @return pointer to the clock ratios that we should use
|
||||
*/
|
||||
struct arm_clk_ratios *get_arm_clk_ratios(void);
|
||||
|
||||
/*
|
||||
* Initialize clock for the device
|
||||
*/
|
||||
struct mem_timings;
|
||||
void system_clock_init(struct mem_timings *mem,
|
||||
struct arm_clk_ratios *arm_clk_ratio);
|
||||
|
||||
#endif
|
|
@ -0,0 +1,691 @@
|
|||
/*
|
||||
* This file is part of the coreboot project.
|
||||
*
|
||||
* Copyright (C) 2010 Samsung Electronics
|
||||
*
|
||||
* 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; version 2 of 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include <console/console.h>
|
||||
#include <stdlib.h>
|
||||
#include <assert.h>
|
||||
#include <arch/io.h>
|
||||
#include "timer.h"
|
||||
#include "clk.h"
|
||||
#include "cpu.h"
|
||||
|
||||
/* input clock of PLL: SMDK5420 has 24MHz input clock */
|
||||
#define CONFIG_SYS_CLK_FREQ 24000000
|
||||
|
||||
static struct arm_clk_ratios arm_clk_ratios[] = {
|
||||
{
|
||||
.arm_freq_mhz = 600,
|
||||
|
||||
.apll_mdiv = 0xc8,
|
||||
.apll_pdiv = 0x4,
|
||||
.apll_sdiv = 0x1,
|
||||
|
||||
.arm2_ratio = 0x0,
|
||||
.apll_ratio = 0x1,
|
||||
.pclk_dbg_ratio = 0x1,
|
||||
.atb_ratio = 0x2,
|
||||
.periph_ratio = 0x7,
|
||||
.acp_ratio = 0x7,
|
||||
.cpud_ratio = 0x1,
|
||||
.arm_ratio = 0x0,
|
||||
}, {
|
||||
.arm_freq_mhz = 800,
|
||||
|
||||
.apll_mdiv = 0x64,
|
||||
.apll_pdiv = 0x3,
|
||||
.apll_sdiv = 0x0,
|
||||
|
||||
.arm2_ratio = 0x0,
|
||||
.apll_ratio = 0x1,
|
||||
.pclk_dbg_ratio = 0x1,
|
||||
.atb_ratio = 0x3,
|
||||
.periph_ratio = 0x7,
|
||||
.acp_ratio = 0x7,
|
||||
.cpud_ratio = 0x2,
|
||||
.arm_ratio = 0x0,
|
||||
}, {
|
||||
.arm_freq_mhz = 1000,
|
||||
|
||||
.apll_mdiv = 0x7d,
|
||||
.apll_pdiv = 0x3,
|
||||
.apll_sdiv = 0x0,
|
||||
|
||||
.arm2_ratio = 0x0,
|
||||
.apll_ratio = 0x1,
|
||||
.pclk_dbg_ratio = 0x1,
|
||||
.atb_ratio = 0x4,
|
||||
.periph_ratio = 0x7,
|
||||
.acp_ratio = 0x7,
|
||||
.cpud_ratio = 0x2,
|
||||
.arm_ratio = 0x0,
|
||||
}, {
|
||||
.arm_freq_mhz = 1200,
|
||||
|
||||
.apll_mdiv = 0x96,
|
||||
.apll_pdiv = 0x3,
|
||||
.apll_sdiv = 0x0,
|
||||
|
||||
.arm2_ratio = 0x0,
|
||||
.apll_ratio = 0x3,
|
||||
.pclk_dbg_ratio = 0x1,
|
||||
.atb_ratio = 0x5,
|
||||
.periph_ratio = 0x7,
|
||||
.acp_ratio = 0x7,
|
||||
.cpud_ratio = 0x3,
|
||||
.arm_ratio = 0x0,
|
||||
}, {
|
||||
.arm_freq_mhz = 1400,
|
||||
|
||||
.apll_mdiv = 0xaf,
|
||||
.apll_pdiv = 0x3,
|
||||
.apll_sdiv = 0x0,
|
||||
|
||||
.arm2_ratio = 0x0,
|
||||
.apll_ratio = 0x3,
|
||||
.pclk_dbg_ratio = 0x1,
|
||||
.atb_ratio = 0x6,
|
||||
.periph_ratio = 0x7,
|
||||
.acp_ratio = 0x7,
|
||||
.cpud_ratio = 0x3,
|
||||
.arm_ratio = 0x0,
|
||||
}, {
|
||||
.arm_freq_mhz = 1700,
|
||||
|
||||
.apll_mdiv = 0x1a9,
|
||||
.apll_pdiv = 0x6,
|
||||
.apll_sdiv = 0x0,
|
||||
|
||||
.arm2_ratio = 0x0,
|
||||
.apll_ratio = 0x3,
|
||||
.pclk_dbg_ratio = 0x1,
|
||||
.atb_ratio = 0x6,
|
||||
.periph_ratio = 0x7,
|
||||
.acp_ratio = 0x7,
|
||||
.cpud_ratio = 0x3,
|
||||
.arm_ratio = 0x0,
|
||||
}
|
||||
};
|
||||
|
||||
/* src_bit div_bit prediv_bit */
|
||||
static struct clk_bit_info clk_bit_info[PERIPH_ID_COUNT] = {
|
||||
{0, 4, 0, -1},
|
||||
{4, 4, 4, -1},
|
||||
{8, 4, 8, -1},
|
||||
{12, 4, 12, -1},
|
||||
{0, 4, 0, 8},
|
||||
{4, 4, 16, 24},
|
||||
{8, 4, 0, 8},
|
||||
{12, 4, 16, 24},
|
||||
{-1, -1, -1, -1},
|
||||
{16, 4, 0, 8}, /* PERIPH_ID_SROMC */
|
||||
{20, 4, 16, 24},
|
||||
{24, 4, 0, 8},
|
||||
{0, 4, 0, 4},
|
||||
{4, 4, 12, 16},
|
||||
{-1, 4, -1, -1},
|
||||
{-1, 4, -1, -1},
|
||||
{-1, 4, 24, 0},
|
||||
{-1, 4, 24, 0},
|
||||
{-1, 4, 24, 0},
|
||||
{-1, 4, 24, 0},
|
||||
{-1, 4, 24, 0},
|
||||
{-1, 4, 24, 0},
|
||||
{-1, 4, 24, 0},
|
||||
{-1, 4, 24, 0},
|
||||
{24, 4, 0, -1},
|
||||
{24, 4, 0, -1},
|
||||
{24, 4, 0, -1},
|
||||
{24, 4, 0, -1},
|
||||
{24, 4, 0, -1},
|
||||
{-1, -1, -1, -1},
|
||||
{-1, -1, -1, -1},
|
||||
{-1, -1, -1, -1}, /* PERIPH_ID_I2S1 */
|
||||
{24, 1, 20, -1}, /* PERIPH_ID_SATA */
|
||||
};
|
||||
|
||||
/* Epll Clock division values to achive different frequency output */
|
||||
static struct st_epll_con_val epll_div[] = {
|
||||
{ 192000000, 0, 48, 3, 1, 0 },
|
||||
{ 180000000, 0, 45, 3, 1, 0 },
|
||||
{ 73728000, 1, 73, 3, 3, 47710 },
|
||||
{ 67737600, 1, 90, 4, 3, 20762 },
|
||||
{ 49152000, 0, 49, 3, 3, 9961 },
|
||||
{ 45158400, 0, 45, 3, 3, 10381 },
|
||||
{ 180633600, 0, 45, 3, 1, 10381 }
|
||||
};
|
||||
|
||||
/* exynos5: return pll clock frequency */
|
||||
unsigned long get_pll_clk(int pllreg)
|
||||
{
|
||||
struct exynos5_clock *clk =
|
||||
samsung_get_base_clock();
|
||||
unsigned long r, m, p, s, k = 0, mask, fout;
|
||||
unsigned int freq;
|
||||
|
||||
switch (pllreg) {
|
||||
case APLL:
|
||||
r = readl(&clk->apll_con0);
|
||||
break;
|
||||
case BPLL:
|
||||
r = readl(&clk->bpll_con0);
|
||||
break;
|
||||
case MPLL:
|
||||
r = readl(&clk->mpll_con0);
|
||||
break;
|
||||
case EPLL:
|
||||
r = readl(&clk->epll_con0);
|
||||
k = readl(&clk->epll_con1);
|
||||
break;
|
||||
case VPLL:
|
||||
r = readl(&clk->vpll_con0);
|
||||
k = readl(&clk->vpll_con1);
|
||||
break;
|
||||
default:
|
||||
printk(BIOS_DEBUG, "Unsupported PLL (%d)\n", pllreg);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* APLL_CON: MIDV [25:16]
|
||||
* MPLL_CON: MIDV [25:16]
|
||||
* EPLL_CON: MIDV [24:16]
|
||||
* VPLL_CON: MIDV [24:16]
|
||||
*/
|
||||
if (pllreg == APLL || pllreg == BPLL || pllreg == MPLL)
|
||||
mask = 0x3ff;
|
||||
else
|
||||
mask = 0x1ff;
|
||||
|
||||
m = (r >> 16) & mask;
|
||||
|
||||
/* PDIV [13:8] */
|
||||
p = (r >> 8) & 0x3f;
|
||||
/* SDIV [2:0] */
|
||||
s = r & 0x7;
|
||||
|
||||
freq = CONFIG_SYS_CLK_FREQ;
|
||||
|
||||
if (pllreg == EPLL) {
|
||||
k = k & 0xffff;
|
||||
/* FOUT = (MDIV + K / 65536) * FIN / (PDIV * 2^SDIV) */
|
||||
fout = (m + k / 65536) * (freq / (p * (1 << s)));
|
||||
} else if (pllreg == VPLL) {
|
||||
k = k & 0xfff;
|
||||
/* FOUT = (MDIV + K / 1024) * FIN / (PDIV * 2^SDIV) */
|
||||
fout = (m + k / 1024) * (freq / (p * (1 << s)));
|
||||
} else {
|
||||
/* FOUT = MDIV * FIN / (PDIV * 2^SDIV) */
|
||||
fout = m * (freq / (p * (1 << s)));
|
||||
}
|
||||
|
||||
return fout;
|
||||
}
|
||||
|
||||
unsigned long clock_get_periph_rate(enum periph_id peripheral)
|
||||
{
|
||||
struct exynos5_clock *clk =
|
||||
samsung_get_base_clock();
|
||||
struct clk_bit_info *bit_info = &clk_bit_info[peripheral];
|
||||
unsigned long sclk, sub_clk;
|
||||
unsigned int src, div, sub_div;
|
||||
|
||||
switch (peripheral) {
|
||||
case PERIPH_ID_UART0:
|
||||
case PERIPH_ID_UART1:
|
||||
case PERIPH_ID_UART2:
|
||||
case PERIPH_ID_UART3:
|
||||
src = readl(&clk->src_peric0);
|
||||
div = readl(&clk->div_peric0);
|
||||
break;
|
||||
case PERIPH_ID_PWM0:
|
||||
case PERIPH_ID_PWM1:
|
||||
case PERIPH_ID_PWM2:
|
||||
case PERIPH_ID_PWM3:
|
||||
case PERIPH_ID_PWM4:
|
||||
src = readl(&clk->src_peric0);
|
||||
div = readl(&clk->div_peric3);
|
||||
break;
|
||||
case PERIPH_ID_SPI0:
|
||||
case PERIPH_ID_SPI1:
|
||||
src = readl(&clk->src_peric1);
|
||||
div = readl(&clk->div_peric1);
|
||||
break;
|
||||
case PERIPH_ID_SPI2:
|
||||
src = readl(&clk->src_peric1);
|
||||
div = readl(&clk->div_peric2);
|
||||
break;
|
||||
case PERIPH_ID_SPI3:
|
||||
case PERIPH_ID_SPI4:
|
||||
src = readl(&clk->sclk_src_isp);
|
||||
div = readl(&clk->sclk_div_isp);
|
||||
break;
|
||||
case PERIPH_ID_SATA:
|
||||
src = readl(&clk->src_fsys);
|
||||
div = readl(&clk->div_fsys0);
|
||||
break;
|
||||
case PERIPH_ID_SDMMC0:
|
||||
case PERIPH_ID_SDMMC1:
|
||||
case PERIPH_ID_SDMMC2:
|
||||
case PERIPH_ID_SDMMC3:
|
||||
src = readl(&clk->src_fsys);
|
||||
div = readl(&clk->div_fsys1);
|
||||
break;
|
||||
case PERIPH_ID_I2C0:
|
||||
case PERIPH_ID_I2C1:
|
||||
case PERIPH_ID_I2C2:
|
||||
case PERIPH_ID_I2C3:
|
||||
case PERIPH_ID_I2C4:
|
||||
case PERIPH_ID_I2C5:
|
||||
case PERIPH_ID_I2C6:
|
||||
case PERIPH_ID_I2C7:
|
||||
sclk = get_pll_clk(MPLL);
|
||||
sub_div = ((readl(&clk->div_top1) >> bit_info->div_bit) & 0x7) + 1;
|
||||
div = ((readl(&clk->div_top0) >> bit_info->prediv_bit) & 0x7) + 1;
|
||||
return (sclk / sub_div) / div;
|
||||
default:
|
||||
printk(BIOS_DEBUG, "%s: invalid peripheral %d", __func__, peripheral);
|
||||
return -1;
|
||||
};
|
||||
|
||||
src = (src >> bit_info->src_bit) & ((1 << bit_info->n_src_bits) - 1);
|
||||
if (peripheral == PERIPH_ID_SATA) {
|
||||
if (src)
|
||||
sclk = get_pll_clk(BPLL);
|
||||
else
|
||||
sclk = get_pll_clk(MPLL);
|
||||
} else {
|
||||
if (src == SRC_MPLL)
|
||||
sclk = get_pll_clk(MPLL);
|
||||
else if (src == SRC_EPLL)
|
||||
sclk = get_pll_clk(EPLL);
|
||||
else if (src == SRC_VPLL)
|
||||
sclk = get_pll_clk(VPLL);
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
sub_div = (div >> bit_info->div_bit) & 0xf;
|
||||
sub_clk = sclk / (sub_div + 1);
|
||||
|
||||
if (peripheral == PERIPH_ID_SDMMC0 || peripheral == PERIPH_ID_SDMMC2) {
|
||||
div = (div >> bit_info->prediv_bit) & 0xff;
|
||||
return sub_clk / (div + 1);
|
||||
}
|
||||
|
||||
return sub_clk;
|
||||
}
|
||||
|
||||
/* exynos5: return ARM clock frequency */
|
||||
unsigned long get_arm_clk(void)
|
||||
{
|
||||
struct exynos5_clock *clk =
|
||||
samsung_get_base_clock();
|
||||
unsigned long div;
|
||||
unsigned long armclk;
|
||||
unsigned int arm_ratio;
|
||||
unsigned int arm2_ratio;
|
||||
|
||||
div = readl(&clk->div_cpu0);
|
||||
|
||||
/* ARM_RATIO: [2:0], ARM2_RATIO: [30:28] */
|
||||
arm_ratio = (div >> 0) & 0x7;
|
||||
arm2_ratio = (div >> 28) & 0x7;
|
||||
|
||||
armclk = get_pll_clk(APLL) / (arm_ratio + 1);
|
||||
armclk /= (arm2_ratio + 1);
|
||||
|
||||
return armclk;
|
||||
}
|
||||
|
||||
struct arm_clk_ratios *get_arm_clk_ratios(void)
|
||||
{
|
||||
struct arm_clk_ratios *arm_ratio;
|
||||
unsigned long arm_freq = 1700; /* FIXME: use get_arm_clk() */
|
||||
int i;
|
||||
|
||||
for (i = 0, arm_ratio = arm_clk_ratios; i < ARRAY_SIZE(arm_clk_ratios);
|
||||
i++, arm_ratio++) {
|
||||
if (arm_ratio->arm_freq_mhz == arm_freq)
|
||||
return arm_ratio;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* exynos5: set the mmc clock */
|
||||
void set_mmc_clk(int dev_index, unsigned int div)
|
||||
{
|
||||
struct exynos5_clock *clk =
|
||||
samsung_get_base_clock();
|
||||
unsigned int *addr;
|
||||
unsigned int val;
|
||||
|
||||
/*
|
||||
* CLK_DIV_FSYS1
|
||||
* MMC0_PRE_RATIO [15:8], MMC1_PRE_RATIO [31:24]
|
||||
* CLK_DIV_FSYS2
|
||||
* MMC2_PRE_RATIO [15:8], MMC3_PRE_RATIO [31:24]
|
||||
*/
|
||||
if (dev_index < 2) {
|
||||
addr = &clk->div_fsys1;
|
||||
} else {
|
||||
addr = &clk->div_fsys2;
|
||||
dev_index -= 2;
|
||||
}
|
||||
|
||||
val = readl(addr);
|
||||
val &= ~(0xff << ((dev_index << 4) + 8));
|
||||
val |= (div & 0xff) << ((dev_index << 4) + 8);
|
||||
writel(val, addr);
|
||||
}
|
||||
|
||||
void clock_ll_set_pre_ratio(enum periph_id periph_id, unsigned divisor)
|
||||
{
|
||||
struct exynos5_clock *clk =
|
||||
samsung_get_base_clock();
|
||||
unsigned shift;
|
||||
unsigned mask = 0xff;
|
||||
u32 *reg;
|
||||
|
||||
/*
|
||||
* For now we only handle a very small subset of peipherals here.
|
||||
* Others will need to (and do) mangle the clock registers
|
||||
* themselves, At some point it is hoped that this function can work
|
||||
* from a table or calculated register offset / mask. For now this
|
||||
* is at least better than spreading clock control code around
|
||||
* U-Boot.
|
||||
*/
|
||||
switch (periph_id) {
|
||||
case PERIPH_ID_SPI0:
|
||||
reg = &clk->div_peric1;
|
||||
shift = 8;
|
||||
break;
|
||||
case PERIPH_ID_SPI1:
|
||||
reg = &clk->div_peric1;
|
||||
shift = 24;
|
||||
break;
|
||||
case PERIPH_ID_SPI2:
|
||||
reg = &clk->div_peric2;
|
||||
shift = 8;
|
||||
break;
|
||||
case PERIPH_ID_SPI3:
|
||||
reg = &clk->sclk_div_isp;
|
||||
shift = 4;
|
||||
break;
|
||||
case PERIPH_ID_SPI4:
|
||||
reg = &clk->sclk_div_isp;
|
||||
shift = 16;
|
||||
break;
|
||||
default:
|
||||
printk(BIOS_DEBUG, "%s: Unsupported peripheral ID %d\n", __func__,
|
||||
periph_id);
|
||||
return;
|
||||
}
|
||||
clrsetbits_le32(reg, mask << shift, (divisor & mask) << shift);
|
||||
}
|
||||
|
||||
void clock_ll_set_ratio(enum periph_id periph_id, unsigned divisor)
|
||||
{
|
||||
struct exynos5_clock *clk =
|
||||
samsung_get_base_clock();
|
||||
unsigned shift;
|
||||
unsigned mask = 0xff;
|
||||
u32 *reg;
|
||||
|
||||
switch (periph_id) {
|
||||
case PERIPH_ID_SPI0:
|
||||
reg = &clk->div_peric1;
|
||||
shift = 0;
|
||||
break;
|
||||
case PERIPH_ID_SPI1:
|
||||
reg = &clk->div_peric1;
|
||||
shift = 16;
|
||||
break;
|
||||
case PERIPH_ID_SPI2:
|
||||
reg = &clk->div_peric2;
|
||||
shift = 0;
|
||||
break;
|
||||
case PERIPH_ID_SPI3:
|
||||
reg = &clk->sclk_div_isp;
|
||||
shift = 0;
|
||||
break;
|
||||
case PERIPH_ID_SPI4:
|
||||
reg = &clk->sclk_div_isp;
|
||||
shift = 12;
|
||||
break;
|
||||
default:
|
||||
printk(BIOS_DEBUG, "%s: Unsupported peripheral ID %d\n", __func__,
|
||||
periph_id);
|
||||
return;
|
||||
}
|
||||
clrsetbits_le32(reg, mask << shift, (divisor & mask) << shift);
|
||||
}
|
||||
|
||||
/**
|
||||
* Linearly searches for the most accurate main and fine stage clock scalars
|
||||
* (divisors) for a specified target frequency and scalar bit sizes by checking
|
||||
* all multiples of main_scalar_bits values. Will always return scalars up to or
|
||||
* slower than target.
|
||||
*
|
||||
* @param main_scalar_bits Number of main scalar bits, must be > 0 and < 32
|
||||
* @param fine_scalar_bits Number of fine scalar bits, must be > 0 and < 32
|
||||
* @param input_freq Clock frequency to be scaled in Hz
|
||||
* @param target_freq Desired clock frequency in Hz
|
||||
* @param best_fine_scalar Pointer to store the fine stage divisor
|
||||
*
|
||||
* @return best_main_scalar Main scalar for desired frequency or -1 if none
|
||||
* found
|
||||
*/
|
||||
static int clock_calc_best_scalar(unsigned int main_scaler_bits,
|
||||
unsigned int fine_scalar_bits, unsigned int input_rate,
|
||||
unsigned int target_rate, unsigned int *best_fine_scalar)
|
||||
{
|
||||
int i;
|
||||
int best_main_scalar = -1;
|
||||
unsigned int best_error = target_rate;
|
||||
const unsigned int cap = (1 << fine_scalar_bits) - 1;
|
||||
const unsigned int loops = 1 << main_scaler_bits;
|
||||
|
||||
printk(BIOS_DEBUG, "Input Rate is %u, Target is %u, Cap is %u\n", input_rate,
|
||||
target_rate, cap);
|
||||
|
||||
ASSERT(best_fine_scalar != NULL);
|
||||
ASSERT(main_scaler_bits <= fine_scalar_bits);
|
||||
|
||||
*best_fine_scalar = 1;
|
||||
|
||||
if (input_rate == 0 || target_rate == 0)
|
||||
return -1;
|
||||
|
||||
if (target_rate >= input_rate)
|
||||
return 1;
|
||||
|
||||
for (i = 1; i <= loops; i++) {
|
||||
const unsigned int effective_div = MAX(MIN(input_rate / i /
|
||||
target_rate, cap), 1);
|
||||
const unsigned int effective_rate = input_rate / i /
|
||||
effective_div;
|
||||
const int error = target_rate - effective_rate;
|
||||
|
||||
printk(BIOS_DEBUG, "%d|effdiv:%u, effrate:%u, error:%d\n", i, effective_div,
|
||||
effective_rate, error);
|
||||
|
||||
if (error >= 0 && error <= best_error) {
|
||||
best_error = error;
|
||||
best_main_scalar = i;
|
||||
*best_fine_scalar = effective_div;
|
||||
}
|
||||
}
|
||||
|
||||
return best_main_scalar;
|
||||
}
|
||||
|
||||
int clock_set_rate(enum periph_id periph_id, unsigned int rate)
|
||||
{
|
||||
int main;
|
||||
unsigned int fine;
|
||||
|
||||
switch (periph_id) {
|
||||
case PERIPH_ID_SPI0:
|
||||
case PERIPH_ID_SPI1:
|
||||
case PERIPH_ID_SPI2:
|
||||
case PERIPH_ID_SPI3:
|
||||
case PERIPH_ID_SPI4:
|
||||
main = clock_calc_best_scalar(4, 8, 400000000, rate, &fine);
|
||||
if (main < 0) {
|
||||
printk(BIOS_DEBUG, "%s: Cannot set clock rate for periph %d",
|
||||
__func__, periph_id);
|
||||
return -1;
|
||||
}
|
||||
clock_ll_set_ratio(periph_id, main - 1);
|
||||
clock_ll_set_pre_ratio(periph_id, fine - 1);
|
||||
break;
|
||||
default:
|
||||
printk(BIOS_DEBUG, "%s: Unsupported peripheral ID %d\n", __func__,
|
||||
periph_id);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int clock_set_mshci(enum periph_id peripheral)
|
||||
{
|
||||
struct exynos5_clock *clk =
|
||||
samsung_get_base_clock();
|
||||
u32 *addr;
|
||||
unsigned int clock;
|
||||
unsigned int tmp;
|
||||
unsigned int i;
|
||||
|
||||
/* get mpll clock */
|
||||
clock = get_pll_clk(MPLL) / 1000000;
|
||||
|
||||
/*
|
||||
* CLK_DIV_FSYS1
|
||||
* MMC0_PRE_RATIO [15:8], MMC0_RATIO [3:0]
|
||||
* CLK_DIV_FSYS2
|
||||
* MMC2_PRE_RATIO [15:8], MMC2_RATIO [3:0]
|
||||
*/
|
||||
switch (peripheral) {
|
||||
case PERIPH_ID_SDMMC0:
|
||||
addr = &clk->div_fsys1;
|
||||
break;
|
||||
case PERIPH_ID_SDMMC2:
|
||||
addr = &clk->div_fsys2;
|
||||
break;
|
||||
default:
|
||||
printk(BIOS_DEBUG, "invalid peripheral\n");
|
||||
return -1;
|
||||
}
|
||||
tmp = readl(addr) & ~0xff0f;
|
||||
for (i = 0; i <= 0xf; i++) {
|
||||
if ((clock / (i + 1)) <= 400) {
|
||||
writel(tmp | i << 0, addr);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int clock_epll_set_rate(unsigned long rate)
|
||||
{
|
||||
unsigned int epll_con, epll_con_k;
|
||||
unsigned int i;
|
||||
unsigned int lockcnt;
|
||||
unsigned int start;
|
||||
struct exynos5_clock *clk =
|
||||
samsung_get_base_clock();
|
||||
|
||||
epll_con = readl(&clk->epll_con0);
|
||||
epll_con &= ~((EPLL_CON0_LOCK_DET_EN_MASK <<
|
||||
EPLL_CON0_LOCK_DET_EN_SHIFT) |
|
||||
EPLL_CON0_MDIV_MASK << EPLL_CON0_MDIV_SHIFT |
|
||||
EPLL_CON0_PDIV_MASK << EPLL_CON0_PDIV_SHIFT |
|
||||
EPLL_CON0_SDIV_MASK << EPLL_CON0_SDIV_SHIFT);
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(epll_div); i++) {
|
||||
if (epll_div[i].freq_out == rate)
|
||||
break;
|
||||
}
|
||||
|
||||
if (i == ARRAY_SIZE(epll_div))
|
||||
return -1;
|
||||
|
||||
epll_con_k = epll_div[i].k_dsm << 0;
|
||||
epll_con |= epll_div[i].en_lock_det << EPLL_CON0_LOCK_DET_EN_SHIFT;
|
||||
epll_con |= epll_div[i].m_div << EPLL_CON0_MDIV_SHIFT;
|
||||
epll_con |= epll_div[i].p_div << EPLL_CON0_PDIV_SHIFT;
|
||||
epll_con |= epll_div[i].s_div << EPLL_CON0_SDIV_SHIFT;
|
||||
|
||||
/*
|
||||
* Required period ( in cycles) to genarate a stable clock output.
|
||||
* The maximum clock time can be up to 3000 * PDIV cycles of PLLs
|
||||
* frequency input (as per spec)
|
||||
*/
|
||||
lockcnt = 3000 * epll_div[i].p_div;
|
||||
|
||||
writel(lockcnt, &clk->epll_lock);
|
||||
writel(epll_con, &clk->epll_con0);
|
||||
writel(epll_con_k, &clk->epll_con1);
|
||||
|
||||
start = get_timer(0);
|
||||
|
||||
while (!(readl(&clk->epll_con0) &
|
||||
(0x1 << EXYNOS5_EPLLCON0_LOCKED_SHIFT))) {
|
||||
if (get_timer(start) > TIMEOUT_EPLL_LOCK) {
|
||||
printk(BIOS_DEBUG, "%s: Timeout waiting for EPLL lock\n", __func__);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void clock_select_i2s_clk_source(void)
|
||||
{
|
||||
struct exynos5_clock *clk =
|
||||
samsung_get_base_clock();
|
||||
|
||||
clrsetbits_le32(&clk->src_peric1, AUDIO1_SEL_MASK,
|
||||
(CLK_SRC_SCLK_EPLL));
|
||||
}
|
||||
|
||||
int clock_set_i2s_clk_prescaler(unsigned int src_frq, unsigned int dst_frq)
|
||||
{
|
||||
struct exynos5_clock *clk =
|
||||
samsung_get_base_clock();
|
||||
unsigned int div ;
|
||||
|
||||
if ((dst_frq == 0) || (src_frq == 0)) {
|
||||
printk(BIOS_DEBUG, "%s: Invalid requency input for prescaler\n", __func__);
|
||||
printk(BIOS_DEBUG, "src frq = %d des frq = %d ", src_frq, dst_frq);
|
||||
return -1;
|
||||
}
|
||||
|
||||
div = (src_frq / dst_frq);
|
||||
if (div > AUDIO_1_RATIO_MASK) {
|
||||
printk(BIOS_DEBUG, "%s: Frequency ratio is out of range\n", __func__);
|
||||
printk(BIOS_DEBUG, "src frq = %d des frq = %d ", src_frq, dst_frq);
|
||||
return -1;
|
||||
}
|
||||
clrsetbits_le32(&clk->div_peric4, AUDIO_1_RATIO_MASK,
|
||||
(div & AUDIO_1_RATIO_MASK));
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,445 @@
|
|||
/*
|
||||
* This file is part of the coreboot project.
|
||||
*
|
||||
* Copyright (C) 2012 Samsung Electronics
|
||||
*
|
||||
* 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; version 2 of 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
/* Clock setup for SMDK5420 board based on EXYNOS5 */
|
||||
|
||||
#include <console/console.h>
|
||||
#include <delay.h>
|
||||
#include "clk.h"
|
||||
#include "cpu.h"
|
||||
#include "dp.h"
|
||||
#include "setup.h"
|
||||
|
||||
void system_clock_init(struct mem_timings *mem,
|
||||
struct arm_clk_ratios *arm_clk_ratio)
|
||||
{
|
||||
struct exynos5_clock *clk = (struct exynos5_clock *)EXYNOS5_CLOCK_BASE;
|
||||
struct exynos5_mct_regs *mct_regs =
|
||||
(struct exynos5_mct_regs *)EXYNOS5_MULTI_CORE_TIMER_BASE;
|
||||
u32 val, tmp;
|
||||
|
||||
/* Turn on the MCT as early as possible. */
|
||||
mct_regs->g_tcon |= (1 << 8);
|
||||
|
||||
clrbits_le32(&clk->src_cpu, MUX_APLL_SEL_MASK);
|
||||
do {
|
||||
val = readl(&clk->mux_stat_cpu);
|
||||
} while ((val | MUX_APLL_SEL_MASK) != val);
|
||||
|
||||
clrbits_le32(&clk->src_core1, MUX_MPLL_SEL_MASK);
|
||||
do {
|
||||
val = readl(&clk->mux_stat_core1);
|
||||
} while ((val | MUX_MPLL_SEL_MASK) != val);
|
||||
|
||||
clrbits_le32(&clk->src_top2, MUX_CPLL_SEL_MASK);
|
||||
clrbits_le32(&clk->src_top2, MUX_EPLL_SEL_MASK);
|
||||
clrbits_le32(&clk->src_top2, MUX_VPLL_SEL_MASK);
|
||||
clrbits_le32(&clk->src_top2, MUX_GPLL_SEL_MASK);
|
||||
tmp = MUX_CPLL_SEL_MASK | MUX_EPLL_SEL_MASK | MUX_VPLL_SEL_MASK
|
||||
| MUX_GPLL_SEL_MASK;
|
||||
do {
|
||||
val = readl(&clk->mux_stat_top2);
|
||||
} while ((val | tmp) != val);
|
||||
|
||||
clrbits_le32(&clk->src_cdrex, MUX_BPLL_SEL_MASK);
|
||||
do {
|
||||
val = readl(&clk->mux_stat_cdrex);
|
||||
} while ((val | MUX_BPLL_SEL_MASK) != val);
|
||||
|
||||
/* PLL locktime */
|
||||
writel(APLL_LOCK_VAL, &clk->apll_lock);
|
||||
|
||||
writel(MPLL_LOCK_VAL, &clk->mpll_lock);
|
||||
|
||||
writel(BPLL_LOCK_VAL, &clk->bpll_lock);
|
||||
|
||||
writel(CPLL_LOCK_VAL, &clk->cpll_lock);
|
||||
|
||||
writel(GPLL_LOCK_VAL, &clk->gpll_lock);
|
||||
|
||||
writel(EPLL_LOCK_VAL, &clk->epll_lock);
|
||||
|
||||
writel(VPLL_LOCK_VAL, &clk->vpll_lock);
|
||||
|
||||
writel(CLK_REG_DISABLE, &clk->pll_div2_sel);
|
||||
|
||||
writel(MUX_HPM_SEL_MASK, &clk->src_cpu);
|
||||
do {
|
||||
val = readl(&clk->mux_stat_cpu);
|
||||
} while ((val | HPM_SEL_SCLK_MPLL) != val);
|
||||
|
||||
val = arm_clk_ratio->arm2_ratio << 28
|
||||
| arm_clk_ratio->apll_ratio << 24
|
||||
| arm_clk_ratio->pclk_dbg_ratio << 20
|
||||
| arm_clk_ratio->atb_ratio << 16
|
||||
| arm_clk_ratio->periph_ratio << 12
|
||||
| arm_clk_ratio->acp_ratio << 8
|
||||
| arm_clk_ratio->cpud_ratio << 4
|
||||
| arm_clk_ratio->arm_ratio;
|
||||
writel(val, &clk->div_cpu0);
|
||||
do {
|
||||
val = readl(&clk->div_stat_cpu0);
|
||||
} while (0 != val);
|
||||
|
||||
writel(CLK_DIV_CPU1_VAL, &clk->div_cpu1);
|
||||
do {
|
||||
val = readl(&clk->div_stat_cpu1);
|
||||
} while (0 != val);
|
||||
|
||||
/* Set APLL */
|
||||
writel(APLL_CON1_VAL, &clk->apll_con1);
|
||||
val = set_pll(arm_clk_ratio->apll_mdiv, arm_clk_ratio->apll_pdiv,
|
||||
arm_clk_ratio->apll_sdiv);
|
||||
writel(val, &clk->apll_con0);
|
||||
while ((readl(&clk->apll_con0) & APLL_CON0_LOCKED) == 0)
|
||||
;
|
||||
|
||||
/* Set MPLL */
|
||||
writel(MPLL_CON1_VAL, &clk->mpll_con1);
|
||||
val = set_pll(mem->mpll_mdiv, mem->mpll_pdiv, mem->mpll_sdiv);
|
||||
writel(val, &clk->mpll_con0);
|
||||
while ((readl(&clk->mpll_con0) & MPLL_CON0_LOCKED) == 0)
|
||||
;
|
||||
|
||||
/*
|
||||
* Configure MUX_MPLL_FOUT to choose the direct clock source
|
||||
* path and avoid the fixed DIV/2 block to save power
|
||||
*/
|
||||
setbits_le32(&clk->pll_div2_sel, MUX_MPLL_FOUT_SEL);
|
||||
|
||||
/* Set BPLL */
|
||||
if (mem->use_bpll) {
|
||||
writel(BPLL_CON1_VAL, &clk->bpll_con1);
|
||||
val = set_pll(mem->bpll_mdiv, mem->bpll_pdiv, mem->bpll_sdiv);
|
||||
writel(val, &clk->bpll_con0);
|
||||
while ((readl(&clk->bpll_con0) & BPLL_CON0_LOCKED) == 0)
|
||||
;
|
||||
|
||||
setbits_le32(&clk->pll_div2_sel, MUX_BPLL_FOUT_SEL);
|
||||
}
|
||||
|
||||
/* Set CPLL */
|
||||
writel(CPLL_CON1_VAL, &clk->cpll_con1);
|
||||
val = set_pll(mem->cpll_mdiv, mem->cpll_pdiv, mem->cpll_sdiv);
|
||||
writel(val, &clk->cpll_con0);
|
||||
while ((readl(&clk->cpll_con0) & CPLL_CON0_LOCKED) == 0)
|
||||
;
|
||||
|
||||
/* Set GPLL */
|
||||
writel(GPLL_CON1_VAL, &clk->gpll_con1);
|
||||
val = set_pll(mem->gpll_mdiv, mem->gpll_pdiv, mem->gpll_sdiv);
|
||||
writel(val, &clk->gpll_con0);
|
||||
while ((readl(&clk->gpll_con0) & GPLL_CON0_LOCKED) == 0)
|
||||
;
|
||||
|
||||
/* Set EPLL */
|
||||
writel(EPLL_CON2_VAL, &clk->epll_con2);
|
||||
writel(EPLL_CON1_VAL, &clk->epll_con1);
|
||||
val = set_pll(mem->epll_mdiv, mem->epll_pdiv, mem->epll_sdiv);
|
||||
writel(val, &clk->epll_con0);
|
||||
while ((readl(&clk->epll_con0) & EPLL_CON0_LOCKED) == 0)
|
||||
;
|
||||
|
||||
/* Set VPLL */
|
||||
writel(VPLL_CON2_VAL, &clk->vpll_con2);
|
||||
writel(VPLL_CON1_VAL, &clk->vpll_con1);
|
||||
val = set_pll(mem->vpll_mdiv, mem->vpll_pdiv, mem->vpll_sdiv);
|
||||
writel(val, &clk->vpll_con0);
|
||||
while ((readl(&clk->vpll_con0) & VPLL_CON0_LOCKED) == 0)
|
||||
;
|
||||
|
||||
writel(CLK_SRC_CORE0_VAL, &clk->src_core0);
|
||||
writel(CLK_DIV_CORE0_VAL, &clk->div_core0);
|
||||
while (readl(&clk->div_stat_core0) != 0)
|
||||
;
|
||||
|
||||
writel(CLK_DIV_CORE1_VAL, &clk->div_core1);
|
||||
while (readl(&clk->div_stat_core1) != 0)
|
||||
;
|
||||
|
||||
writel(CLK_DIV_SYSRGT_VAL, &clk->div_sysrgt);
|
||||
while (readl(&clk->div_stat_sysrgt) != 0)
|
||||
;
|
||||
|
||||
writel(CLK_DIV_ACP_VAL, &clk->div_acp);
|
||||
while (readl(&clk->div_stat_acp) != 0)
|
||||
;
|
||||
|
||||
writel(CLK_DIV_SYSLFT_VAL, &clk->div_syslft);
|
||||
while (readl(&clk->div_stat_syslft) != 0)
|
||||
;
|
||||
|
||||
writel(CLK_SRC_TOP0_VAL, &clk->src_top0);
|
||||
writel(CLK_SRC_TOP1_VAL, &clk->src_top1);
|
||||
writel(TOP2_VAL, &clk->src_top2);
|
||||
writel(CLK_SRC_TOP3_VAL, &clk->src_top3);
|
||||
|
||||
writel(CLK_DIV_TOP0_VAL, &clk->div_top0);
|
||||
while (readl(&clk->div_stat_top0))
|
||||
;
|
||||
|
||||
writel(CLK_DIV_TOP1_VAL, &clk->div_top1);
|
||||
while (readl(&clk->div_stat_top1))
|
||||
;
|
||||
|
||||
writel(CLK_SRC_LEX_VAL, &clk->src_lex);
|
||||
while (1) {
|
||||
val = readl(&clk->mux_stat_lex);
|
||||
if (val == (val | 1))
|
||||
break;
|
||||
}
|
||||
|
||||
writel(CLK_DIV_LEX_VAL, &clk->div_lex);
|
||||
while (readl(&clk->div_stat_lex))
|
||||
;
|
||||
|
||||
writel(CLK_DIV_R0X_VAL, &clk->div_r0x);
|
||||
while (readl(&clk->div_stat_r0x))
|
||||
;
|
||||
|
||||
writel(CLK_DIV_R0X_VAL, &clk->div_r0x);
|
||||
while (readl(&clk->div_stat_r0x))
|
||||
;
|
||||
|
||||
writel(CLK_DIV_R1X_VAL, &clk->div_r1x);
|
||||
while (readl(&clk->div_stat_r1x))
|
||||
;
|
||||
|
||||
if (mem->use_bpll) {
|
||||
writel(MUX_BPLL_SEL_MASK | MUX_MCLK_CDREX_SEL |
|
||||
MUX_MCLK_DPHY_SEL, &clk->src_cdrex);
|
||||
} else {
|
||||
writel(CLK_REG_DISABLE, &clk->src_cdrex);
|
||||
}
|
||||
|
||||
writel(CLK_DIV_CDREX_VAL, &clk->div_cdrex);
|
||||
while (readl(&clk->div_stat_cdrex))
|
||||
;
|
||||
|
||||
val = readl(&clk->src_cpu);
|
||||
val |= CLK_SRC_CPU_VAL;
|
||||
writel(val, &clk->src_cpu);
|
||||
|
||||
val = readl(&clk->src_top2);
|
||||
val |= CLK_SRC_TOP2_VAL;
|
||||
writel(val, &clk->src_top2);
|
||||
|
||||
val = readl(&clk->src_core1);
|
||||
val |= CLK_SRC_CORE1_VAL;
|
||||
writel(val, &clk->src_core1);
|
||||
|
||||
writel(CLK_SRC_FSYS0_VAL, &clk->src_fsys);
|
||||
writel(CLK_DIV_FSYS0_VAL, &clk->div_fsys0);
|
||||
while (readl(&clk->div_stat_fsys0))
|
||||
;
|
||||
|
||||
writel(CLK_REG_DISABLE, &clk->clkout_cmu_cpu);
|
||||
writel(CLK_REG_DISABLE, &clk->clkout_cmu_core);
|
||||
writel(CLK_REG_DISABLE, &clk->clkout_cmu_acp);
|
||||
writel(CLK_REG_DISABLE, &clk->clkout_cmu_top);
|
||||
writel(CLK_REG_DISABLE, &clk->clkout_cmu_lex);
|
||||
writel(CLK_REG_DISABLE, &clk->clkout_cmu_r0x);
|
||||
writel(CLK_REG_DISABLE, &clk->clkout_cmu_r1x);
|
||||
writel(CLK_REG_DISABLE, &clk->clkout_cmu_cdrex);
|
||||
|
||||
writel(CLK_SRC_PERIC0_VAL, &clk->src_peric0);
|
||||
writel(CLK_DIV_PERIC0_VAL, &clk->div_peric0);
|
||||
|
||||
writel(CLK_SRC_PERIC1_VAL, &clk->src_peric1);
|
||||
writel(CLK_DIV_PERIC1_VAL, &clk->div_peric1);
|
||||
writel(CLK_DIV_PERIC2_VAL, &clk->div_peric2);
|
||||
writel(SCLK_SRC_ISP_VAL, &clk->sclk_src_isp);
|
||||
writel(SCLK_DIV_ISP_VAL, &clk->sclk_div_isp);
|
||||
writel(CLK_DIV_ISP0_VAL, &clk->div_isp0);
|
||||
writel(CLK_DIV_ISP1_VAL, &clk->div_isp1);
|
||||
writel(CLK_DIV_ISP2_VAL, &clk->div_isp2);
|
||||
|
||||
/* FIMD1 SRC CLK SELECTION */
|
||||
writel(CLK_SRC_DISP1_0_VAL, &clk->src_disp1_0);
|
||||
|
||||
val = MMC2_PRE_RATIO_VAL << MMC2_PRE_RATIO_OFFSET
|
||||
| MMC2_RATIO_VAL << MMC2_RATIO_OFFSET
|
||||
| MMC3_PRE_RATIO_VAL << MMC3_PRE_RATIO_OFFSET
|
||||
| MMC3_RATIO_VAL << MMC3_RATIO_OFFSET;
|
||||
writel(val, &clk->div_fsys2);
|
||||
}
|
||||
|
||||
void clock_gate(void)
|
||||
{
|
||||
struct exynos5_clock *clk = (struct exynos5_clock *)EXYNOS5_CLOCK_BASE;
|
||||
|
||||
/* CLK_GATE_IP_SYSRGT */
|
||||
clrbits_le32(&clk->gate_ip_sysrgt, CLK_C2C_MASK);
|
||||
|
||||
/* CLK_GATE_IP_ACP */
|
||||
clrbits_le32(&clk->gate_ip_acp, CLK_SMMUG2D_MASK |
|
||||
CLK_SMMUSSS_MASK |
|
||||
CLK_SMMUMDMA_MASK |
|
||||
CLK_ID_REMAPPER_MASK |
|
||||
CLK_G2D_MASK |
|
||||
CLK_SSS_MASK |
|
||||
CLK_MDMA_MASK |
|
||||
CLK_SECJTAG_MASK);
|
||||
|
||||
/* CLK_GATE_BUS_SYSLFT */
|
||||
clrbits_le32(&clk->gate_bus_syslft, CLK_EFCLK_MASK);
|
||||
|
||||
/* CLK_GATE_IP_ISP0 */
|
||||
clrbits_le32(&clk->gate_ip_isp0, CLK_UART_ISP_MASK |
|
||||
CLK_WDT_ISP_MASK |
|
||||
CLK_PWM_ISP_MASK |
|
||||
CLK_MTCADC_ISP_MASK |
|
||||
CLK_I2C1_ISP_MASK |
|
||||
CLK_I2C0_ISP_MASK |
|
||||
CLK_MPWM_ISP_MASK |
|
||||
CLK_MCUCTL_ISP_MASK |
|
||||
CLK_INT_COMB_ISP_MASK |
|
||||
CLK_SMMU_MCUISP_MASK |
|
||||
CLK_SMMU_SCALERP_MASK |
|
||||
CLK_SMMU_SCALERC_MASK |
|
||||
CLK_SMMU_FD_MASK |
|
||||
CLK_SMMU_DRC_MASK |
|
||||
CLK_SMMU_ISP_MASK |
|
||||
CLK_GICISP_MASK |
|
||||
CLK_ARM9S_MASK |
|
||||
CLK_MCUISP_MASK |
|
||||
CLK_SCALERP_MASK |
|
||||
CLK_SCALERC_MASK |
|
||||
CLK_FD_MASK |
|
||||
CLK_DRC_MASK |
|
||||
CLK_ISP_MASK);
|
||||
|
||||
/* CLK_GATE_IP_ISP1 */
|
||||
clrbits_le32(&clk->gate_ip_isp1, CLK_SPI1_ISP_MASK |
|
||||
CLK_SPI0_ISP_MASK |
|
||||
CLK_SMMU3DNR_MASK |
|
||||
CLK_SMMUDIS1_MASK |
|
||||
CLK_SMMUDIS0_MASK |
|
||||
CLK_SMMUODC_MASK |
|
||||
CLK_3DNR_MASK |
|
||||
CLK_DIS_MASK |
|
||||
CLK_ODC_MASK);
|
||||
|
||||
/* CLK_GATE_SCLK_ISP */
|
||||
clrbits_le32(&clk->gate_sclk_isp, SCLK_MPWM_ISP_MASK);
|
||||
|
||||
/* CLK_GATE_IP_GSCL */
|
||||
clrbits_le32(&clk->gate_ip_gscl, CLK_SMMUFIMC_LITE2_MASK |
|
||||
CLK_SMMUFIMC_LITE1_MASK |
|
||||
CLK_SMMUFIMC_LITE0_MASK |
|
||||
CLK_SMMUGSCL3_MASK |
|
||||
CLK_SMMUGSCL2_MASK |
|
||||
CLK_SMMUGSCL1_MASK |
|
||||
CLK_SMMUGSCL0_MASK |
|
||||
CLK_GSCL_WRAP_B_MASK |
|
||||
CLK_GSCL_WRAP_A_MASK |
|
||||
CLK_CAMIF_TOP_MASK |
|
||||
CLK_GSCL3_MASK |
|
||||
CLK_GSCL2_MASK |
|
||||
CLK_GSCL1_MASK |
|
||||
CLK_GSCL0_MASK);
|
||||
|
||||
/* CLK_GATE_IP_DISP1 */
|
||||
clrbits_le32(&clk->gate_ip_disp1, CLK_SMMUTVX_MASK |
|
||||
CLK_ASYNCTVX_MASK |
|
||||
CLK_HDMI_MASK |
|
||||
CLK_MIXER_MASK |
|
||||
CLK_DSIM1_MASK);
|
||||
|
||||
/* CLK_GATE_IP_MFC */
|
||||
clrbits_le32(&clk->gate_ip_mfc, CLK_SMMUMFCR_MASK |
|
||||
CLK_SMMUMFCL_MASK |
|
||||
CLK_MFC_MASK);
|
||||
|
||||
/* CLK_GATE_IP_GEN */
|
||||
clrbits_le32(&clk->gate_ip_gen, CLK_SMMUMDMA1_MASK |
|
||||
CLK_SMMUJPEG_MASK |
|
||||
CLK_SMMUROTATOR_MASK |
|
||||
CLK_MDMA1_MASK |
|
||||
CLK_JPEG_MASK |
|
||||
CLK_ROTATOR_MASK);
|
||||
|
||||
/* CLK_GATE_IP_FSYS */
|
||||
clrbits_le32(&clk->gate_ip_fsys, CLK_WDT_IOP_MASK |
|
||||
CLK_SMMUMCU_IOP_MASK |
|
||||
CLK_SATA_PHY_I2C_MASK |
|
||||
CLK_SATA_PHY_CTRL_MASK |
|
||||
CLK_MCUCTL_MASK |
|
||||
CLK_NFCON_MASK |
|
||||
CLK_SMMURTIC_MASK |
|
||||
CLK_RTIC_MASK |
|
||||
CLK_MIPI_HSI_MASK |
|
||||
CLK_USBOTG_MASK |
|
||||
CLK_SATA_MASK |
|
||||
CLK_PDMA1_MASK |
|
||||
CLK_PDMA0_MASK |
|
||||
CLK_MCU_IOP_MASK);
|
||||
|
||||
/* CLK_GATE_IP_PERIC */
|
||||
clrbits_le32(&clk->gate_ip_peric, CLK_HS_I2C3_MASK |
|
||||
CLK_HS_I2C2_MASK |
|
||||
CLK_HS_I2C1_MASK |
|
||||
CLK_HS_I2C0_MASK |
|
||||
CLK_AC97_MASK |
|
||||
CLK_SPDIF_MASK |
|
||||
CLK_PCM2_MASK |
|
||||
CLK_PCM1_MASK |
|
||||
CLK_I2S2_MASK |
|
||||
CLK_SPI2_MASK |
|
||||
CLK_SPI0_MASK);
|
||||
|
||||
/*
|
||||
* CLK_GATE_IP_PERIS
|
||||
* Note: Keep CHIPID_APBIF ungated to ensure reading the product ID
|
||||
* register (PRO_ID) works correctly when the OS kernel determines
|
||||
* which chip it is running on.
|
||||
*/
|
||||
clrbits_le32(&clk->gate_ip_peris, CLK_RTC_MASK |
|
||||
CLK_TZPC9_MASK |
|
||||
CLK_TZPC8_MASK |
|
||||
CLK_TZPC7_MASK |
|
||||
CLK_TZPC6_MASK |
|
||||
CLK_TZPC5_MASK |
|
||||
CLK_TZPC4_MASK |
|
||||
CLK_TZPC3_MASK |
|
||||
CLK_TZPC2_MASK |
|
||||
CLK_TZPC1_MASK |
|
||||
CLK_TZPC0_MASK);
|
||||
|
||||
/* CLK_GATE_BLOCK */
|
||||
clrbits_le32(&clk->gate_block, CLK_ACP_MASK);
|
||||
|
||||
/* CLK_GATE_IP_CDREX */
|
||||
clrbits_le32(&clk->gate_ip_cdrex, CLK_DPHY0_MASK |
|
||||
CLK_DPHY1_MASK |
|
||||
CLK_TZASC_DRBXR_MASK);
|
||||
|
||||
}
|
||||
|
||||
void clock_init_dp_clock(void)
|
||||
{
|
||||
struct exynos5_clock *clk = (struct exynos5_clock *)EXYNOS5_CLOCK_BASE;
|
||||
|
||||
/* DP clock enable */
|
||||
setbits_le32(&clk->gate_ip_disp1, CLK_GATE_DP1_ALLOW);
|
||||
|
||||
/* We run DP at 267 Mhz */
|
||||
setbits_le32(&clk->div_disp1_0, CLK_DIV_DISP1_0_FIMD1);
|
||||
}
|
||||
|
|
@ -0,0 +1,181 @@
|
|||
/*
|
||||
* This file is part of the coreboot project.
|
||||
*
|
||||
* Copyright 2013 Google Inc.
|
||||
*
|
||||
* 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; version 2 of 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stddef.h>
|
||||
#include <delay.h>
|
||||
#include <console/console.h>
|
||||
#include <device/device.h>
|
||||
#include <cbmem.h>
|
||||
#include <arch/cache.h>
|
||||
#include "fimd.h"
|
||||
#include "dp-core.h"
|
||||
#include "cpu.h"
|
||||
#include "clk.h"
|
||||
#include "chip.h"
|
||||
|
||||
#define RAM_BASE_KB (CONFIG_SYS_SDRAM_BASE >> 10)
|
||||
#define RAM_SIZE_KB (CONFIG_DRAM_SIZE_MB << 10UL)
|
||||
|
||||
static unsigned int cpu_id;
|
||||
static unsigned int cpu_rev;
|
||||
|
||||
static void set_cpu_id(void)
|
||||
{
|
||||
cpu_id = readl((void *)EXYNOS_PRO_ID);
|
||||
cpu_id = (0xC000 | ((cpu_id & 0x00FFF000) >> 12));
|
||||
|
||||
/*
|
||||
* 0xC200: EXYNOS4210 EVT0
|
||||
* 0xC210: EXYNOS4210 EVT1
|
||||
*/
|
||||
if (cpu_id == 0xC200) {
|
||||
cpu_id |= 0x10;
|
||||
cpu_rev = 0;
|
||||
} else if (cpu_id == 0xC210) {
|
||||
cpu_rev = 1;
|
||||
}
|
||||
}
|
||||
|
||||
/* we distinguish a display port device from a raw graphics device
|
||||
* because there are dramatic differences in startup depending on
|
||||
* graphics usage. To make startup fast and easier to understand and
|
||||
* debug we explicitly name this common case. The alternate approach,
|
||||
* involving lots of machine and callbacks, is hard to debug and
|
||||
* verify.
|
||||
*/
|
||||
static void exynos_displayport_init(device_t dev)
|
||||
{
|
||||
int ret;
|
||||
struct cpu_samsung_exynos5420_config *conf = dev->chip_info;
|
||||
/* put these on the stack. If, at some point, we want to move
|
||||
* this code to a pre-ram stage, it will be much easier.
|
||||
*/
|
||||
vidinfo_t vi;
|
||||
struct exynos5_fimd_panel panel;
|
||||
unsigned long int fb_size;
|
||||
u32 lcdbase;
|
||||
|
||||
memset(&vi, 0, sizeof(vi));
|
||||
memset(&panel, 0, sizeof(panel));
|
||||
|
||||
panel.is_dp = 1; /* Display I/F is eDP */
|
||||
/* while it is true that we did a memset to zero,
|
||||
* we leave some 'set to zero' entries here to make
|
||||
* it clear what's going on. Graphics is confusing.
|
||||
*/
|
||||
panel.is_mipi = 0;
|
||||
panel.fixvclk = 0;
|
||||
panel.ivclk = 0;
|
||||
panel.clkval_f = conf->clkval_f;
|
||||
panel.upper_margin = conf->upper_margin;
|
||||
panel.lower_margin = conf->lower_margin;
|
||||
panel.vsync = conf->vsync;
|
||||
panel.left_margin = conf->left_margin;
|
||||
panel.right_margin = conf->right_margin;
|
||||
panel.hsync = conf->hsync;
|
||||
panel.xres = conf->xres;
|
||||
panel.yres = conf->yres;
|
||||
|
||||
vi.vl_col = conf->xres;
|
||||
vi.vl_row = conf->yres;
|
||||
vi.vl_bpix = conf->bpp;
|
||||
/*
|
||||
* The size is a magic number from hardware. Allocate enough for the
|
||||
* frame buffer and color map.
|
||||
*/
|
||||
fb_size = conf->xres * conf->yres * (conf->bpp / 8);
|
||||
lcdbase = (uintptr_t)cbmem_add(CBMEM_ID_CONSOLE, fb_size + 64*KiB);
|
||||
printk(BIOS_SPEW, "LCD colormap base is %p\n", (void *)(lcdbase));
|
||||
mmio_resource(dev, 0, lcdbase/KiB, 64);
|
||||
vi.cmap = (void *)lcdbase;
|
||||
|
||||
/*
|
||||
* We need to clean and invalidate the framebuffer region and disable
|
||||
* caching as well. We assume that our dcache <--> memory address
|
||||
* space is identity-mapped in 1MB chunks, so align accordingly.
|
||||
*
|
||||
* Note: We may want to do something clever to ensure the framebuffer
|
||||
* region is aligned such that we don't change dcache policy for other
|
||||
* stuff inadvertantly.
|
||||
*
|
||||
* FIXME: Is disabling/re-enabling the MMU entirely necessary?
|
||||
*/
|
||||
uint32_t lower = ALIGN_DOWN(lcdbase, MiB);
|
||||
uint32_t upper = ALIGN_UP(lcdbase + fb_size + 64*KiB, MiB);
|
||||
dcache_clean_invalidate_by_mva(lower, upper - lower);
|
||||
dcache_mmu_disable();
|
||||
mmu_config_range(lower/MiB, (upper - lower)/MiB, DCACHE_OFF);
|
||||
dcache_mmu_enable();
|
||||
|
||||
lcdbase += 64*KiB;
|
||||
mmio_resource(dev, 1, lcdbase/KiB, (fb_size + KiB - 1)/KiB);
|
||||
printk(BIOS_DEBUG,
|
||||
"Initializing Exynos VGA, base %p\n", (void *)lcdbase);
|
||||
memset((void *)lcdbase, 0, fb_size); /* clear the framebuffer */
|
||||
ret = lcd_ctrl_init(&vi, &panel, (void *)lcdbase);
|
||||
}
|
||||
|
||||
static void cpu_init(device_t dev)
|
||||
{
|
||||
exynos_displayport_init(dev);
|
||||
ram_resource(dev, 0, RAM_BASE_KB, RAM_SIZE_KB);
|
||||
|
||||
set_cpu_id();
|
||||
|
||||
printk(BIOS_INFO, "CPU: S5P%X @ %ldMHz\n",
|
||||
cpu_id, get_arm_clk() / (1024*1024));
|
||||
}
|
||||
|
||||
static void cpu_noop(device_t dev)
|
||||
{
|
||||
}
|
||||
|
||||
static struct device_operations cpu_ops = {
|
||||
.read_resources = cpu_noop,
|
||||
.set_resources = cpu_noop,
|
||||
.enable_resources = cpu_init,
|
||||
.init = cpu_noop,
|
||||
.scan_bus = 0,
|
||||
};
|
||||
|
||||
static void enable_exynos5420_dev(device_t dev)
|
||||
{
|
||||
dev->ops = &cpu_ops;
|
||||
}
|
||||
|
||||
struct chip_operations cpu_samsung_exynos5420_ops = {
|
||||
CHIP_NAME("CPU Samsung Exynos 5420")
|
||||
.enable_dev = enable_exynos5420_dev,
|
||||
};
|
||||
|
||||
void exynos5420_config_l2_cache(void)
|
||||
{
|
||||
uint32_t val;
|
||||
|
||||
/*
|
||||
* Bit 9 - L2 tag RAM setup (1 cycle)
|
||||
* Bits 8:6 - L2 tag RAM latency (3 cycles)
|
||||
* Bit 5 - L2 data RAM setup (1 cycle)
|
||||
* Bits 2:0 - L2 data RAM latency (3 cycles)
|
||||
*/
|
||||
val = (1 << 9) | (0x2 << 6) | (1 << 5) | (0x2);
|
||||
write_l2ctlr(val);
|
||||
}
|
|
@ -0,0 +1,130 @@
|
|||
/*
|
||||
* This file is part of the coreboot project.
|
||||
*
|
||||
* Copyright (C) 2010 Samsung Electronics
|
||||
*
|
||||
* 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; version 2 of 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#ifndef CPU_SAMSUNG_EXYNOS5420_CPU_H
|
||||
#define CPU_SAMSUNG_EXYNOS5420_CPU_H
|
||||
|
||||
#include <arch/io.h>
|
||||
|
||||
#define DEVICE_NOT_AVAILABLE 0
|
||||
|
||||
#define EXYNOS_PRO_ID 0x10000000
|
||||
|
||||
/* Address of address of function that copys data from SD or MMC */
|
||||
#define EXYNOS_COPY_MMC_FNPTR_ADDR 0x02020030
|
||||
|
||||
/* Address of address of function that copys data from SPI */
|
||||
#define EXYNOS_COPY_SPI_FNPTR_ADDR 0x02020058
|
||||
|
||||
/* Address of address of function that copys data through USB */
|
||||
#define EXYNOS_COPY_USB_FNPTR_ADDR 0x02020070
|
||||
|
||||
/* Boot mode values */
|
||||
#define EXYNOS_USB_SECONDARY_BOOT 0xfeed0002
|
||||
|
||||
#define EXYNOS_IRAM_SECONDARY_BASE 0x02020018
|
||||
|
||||
#define EXYNOS_I2C_SPACING 0x10000
|
||||
|
||||
/* EXYNOS5 */
|
||||
#define EXYNOS5_GPIO_PART6_BASE 0x03860000 /* Z<6:0> */
|
||||
#define EXYNOS5_PRO_ID 0x10000000
|
||||
#define EXYNOS5_CLOCK_BASE 0x10010000
|
||||
#define EXYNOS5_POWER_BASE 0x10040000
|
||||
#define EXYNOS5_SWRESET 0x10040400
|
||||
#define EXYNOS5_SYSREG_BASE 0x10050000
|
||||
#define EXYNOS5_TZPC1_DECPROT1SET 0x10110810
|
||||
#define EXYNOS5_MULTI_CORE_TIMER_BASE 0x101C0000
|
||||
#define EXYNOS5_WATCHDOG_BASE 0x101D0000
|
||||
#define EXYNOS5_ACE_SFR_BASE 0x10830000
|
||||
#define EXYNOS5_DMC_PHY0_BASE 0x10C00000
|
||||
#define EXYNOS5_DMC_PHY1_BASE 0x10C10000
|
||||
#define EXYNOS5_GPIO_PART4_BASE 0x10D10000 /* V00..V37 */
|
||||
#define EXYNOS5_GPIO_PART5_BASE 0x10D100C0 /* V40..V47 */
|
||||
#define EXYNOS5_DMC_CTRL_BASE 0x10DD0000
|
||||
#define EXYNOS5_GPIO_PART1_BASE 0x11400000 /* A00..Y67 */
|
||||
#define EXYNOS5_GPIO_PART2_BASE 0x11400c00 /* X00..X37 */
|
||||
#define EXYNOS5_USB_HOST_EHCI_BASE 0x12110000
|
||||
#define EXYNOS5_USBPHY_BASE 0x12130000
|
||||
#define EXYNOS5_USBOTG_BASE 0x12140000
|
||||
|
||||
#define EXYNOS5_MMC_BASE 0x12200000
|
||||
#define EXYNOS5_MSHC_BASE 0x12240000
|
||||
|
||||
#define EXYNOS5_SROMC_BASE 0x12250000
|
||||
#define EXYNOS5_UART_BASE 0x12C00000
|
||||
|
||||
#define EXYNOS5_SPI1_BASE 0x12D30000
|
||||
#define EXYNOS5_I2C_BASE 0x12C60000
|
||||
#define EXYNOS5_SPI_BASE 0x12D20000
|
||||
#define EXYNOS5_PWMTIMER_BASE 0x12DD0000
|
||||
#define EXYNOS5_SPI_ISP_BASE 0x131A0000
|
||||
#define EXYNOS5_I2S_BASE 0x12D60000
|
||||
#define EXYNOS5_GPIO_PART3_BASE 0x13400000 /* E00..H17 */
|
||||
#define EXYNOS5_FIMD_BASE 0x14400000
|
||||
#define EXYNOS5_DISP1_CTRL_BASE 0x14420000
|
||||
#define EXYNOS5_MIPI_DSI1_BASE 0x14500000
|
||||
|
||||
#define EXYNOS5_ADC_BASE DEVICE_NOT_AVAILABLE
|
||||
#define EXYNOS5_MODEM_BASE DEVICE_NOT_AVAILABLE
|
||||
|
||||
/* Compatibility defines */
|
||||
#define EXYNOS_POWER_BASE EXYNOS5_POWER_BASE
|
||||
|
||||
/* Marker values stored at the bottom of IRAM stack by SPL */
|
||||
#define EXYNOS5_SPL_MARKER 0xb004f1a9 /* hexspeak word: bootflag */
|
||||
|
||||
/* Distance between each Trust Zone PC register set */
|
||||
#define TZPC_BASE_OFFSET 0x10000
|
||||
|
||||
#define samsung_get_base_adc() ((struct exynos5_adc *)EXYNOS5_ADC_BASE)
|
||||
#define samsung_get_base_clock() ((struct exynos5_clock *)EXYNOS5_CLOCK_BASE)
|
||||
#define samsung_get_base_ace_sfr() ((struct exynos5_ace_sfr *)EXYNOS5_ACE_SFR_BASE)
|
||||
#define samsung_get_base_dsim() ((struct exynos5_dsim *)EXYNOS5_MIPI_DSI1_BASE)
|
||||
#define samsung_get_base_disp_ctrl() ((struct exynos5_disp_ctrl *)EXYNOS5_DISP1_CTRL_BASE)
|
||||
#define samsung_get_base_fimd() ((struct exynos5_fimd *)EXYNOS5_FIMD_BASE)
|
||||
#define samsung_get_base_pro_id() ((struct exynos5_pro_id *)EXYNOS5_PRO_ID)
|
||||
|
||||
#define samsung_get_base_mmc() ((struct exynos5_mmc *)EXYNOS5_MMC_BASE)
|
||||
#define samsung_get_base_mshci() ((struct exynos5_mshci *)EXYNOS5_MSHC_BASE)
|
||||
|
||||
#define samsung_get_base_modem() ((struct exynos5_modem *)EXYNOS5_MODEM_BASE)
|
||||
#define samsung_get_base_sromc() ((struct exynos5_sromc *)EXYNOS5_SROMC_BASE)
|
||||
#define samsung_get_base_swreset() ((struct exynos5_swreset *)EXYNOS5_SWRESET)
|
||||
#define samsung_get_base_sysreg() ((struct exynos5_sysreg *)EXYNOS5_SYSREG_BASE)
|
||||
#define samsung_get_base_timer() ((struct s5p_timer *)EXYNOS5_PWMTIMER_BASE)
|
||||
#define samsung_get_base_uart() ((struct exynos5_uart *)EXYNOS5_UART_BASE)
|
||||
#define samsung_get_base_usb_phy() ((struct exynos5_usb_phy *)EXYNOS5_USBPHY_BASE)
|
||||
#define samsung_get_base_usb_otg() ((struct exynos5_usb_otg *)EXYNOS5_USBOTG_BASE)
|
||||
#define samsung_get_base_watchdog() ((struct exynos5_watchdog *)EXYNOS5_WATCHDOG_BASE)
|
||||
#define samsung_get_base_power() ((struct exynos5_power *)EXYNOS5_POWER_BASE)
|
||||
#define samsung_get_base_i2s() ((struct exynos5_i2s *)EXYNOS5_I2S_BASE)
|
||||
#define samsung_get_base_spi1() ((struct exynos5_spi1 *)EXYNOS5_SPI1_BASE)
|
||||
#define samsung_get_base_i2c() ((struct exynos5_i2c *)EXYNOS5_I2C_BASE)
|
||||
#define samsung_get_base_spi() ((struct exynos5_spi *)EXYNOS5_SPI_BASE)
|
||||
#define samsung_get_base_spi_isp() ((struct exynos5_spi_isp *)EXYNOS5_SPI_ISP_BASE)
|
||||
|
||||
#define EXYNOS5_SPI_NUM_CONTROLLERS 5
|
||||
#define EXYNOS_I2C_MAX_CONTROLLERS 8
|
||||
|
||||
void exynos5420_config_l2_cache(void);
|
||||
|
||||
extern struct tmu_info exynos5420_tmu_info;
|
||||
|
||||
#endif /* _EXYNOS5420_CPU_H */
|
|
@ -0,0 +1,343 @@
|
|||
/*
|
||||
* This file is part of the coreboot 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; version 2 of 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#ifndef CPU_SAMSUNG_EXYNOS5420_DMC_H
|
||||
#define CPU_SAMSUNG_EXYNOS5420_DMC_H
|
||||
|
||||
#ifndef __ASSEMBLER__
|
||||
struct exynos5_dmc {
|
||||
unsigned int concontrol;
|
||||
unsigned int memcontrol;
|
||||
unsigned int memconfig0;
|
||||
unsigned int memconfig1;
|
||||
unsigned int directcmd;
|
||||
unsigned int prechconfig;
|
||||
unsigned int phycontrol0;
|
||||
unsigned char res1[0xc];
|
||||
unsigned int pwrdnconfig;
|
||||
unsigned int timingpzq;
|
||||
unsigned int timingref;
|
||||
unsigned int timingrow;
|
||||
unsigned int timingdata;
|
||||
unsigned int timingpower;
|
||||
unsigned int phystatus;
|
||||
unsigned char res2[0x4];
|
||||
unsigned int chipstatus_ch0;
|
||||
unsigned int chipstatus_ch1;
|
||||
unsigned char res3[0x4];
|
||||
unsigned int mrstatus;
|
||||
unsigned char res4[0x8];
|
||||
unsigned int qoscontrol0;
|
||||
unsigned char resr5[0x4];
|
||||
unsigned int qoscontrol1;
|
||||
unsigned char res6[0x4];
|
||||
unsigned int qoscontrol2;
|
||||
unsigned char res7[0x4];
|
||||
unsigned int qoscontrol3;
|
||||
unsigned char res8[0x4];
|
||||
unsigned int qoscontrol4;
|
||||
unsigned char res9[0x4];
|
||||
unsigned int qoscontrol5;
|
||||
unsigned char res10[0x4];
|
||||
unsigned int qoscontrol6;
|
||||
unsigned char res11[0x4];
|
||||
unsigned int qoscontrol7;
|
||||
unsigned char res12[0x4];
|
||||
unsigned int qoscontrol8;
|
||||
unsigned char res13[0x4];
|
||||
unsigned int qoscontrol9;
|
||||
unsigned char res14[0x4];
|
||||
unsigned int qoscontrol10;
|
||||
unsigned char res15[0x4];
|
||||
unsigned int qoscontrol11;
|
||||
unsigned char res16[0x4];
|
||||
unsigned int qoscontrol12;
|
||||
unsigned char res17[0x4];
|
||||
unsigned int qoscontrol13;
|
||||
unsigned char res18[0x4];
|
||||
unsigned int qoscontrol14;
|
||||
unsigned char res19[0x4];
|
||||
unsigned int qoscontrol15;
|
||||
unsigned char res20[0x14];
|
||||
unsigned int ivcontrol;
|
||||
unsigned int wrtra_config;
|
||||
unsigned int rdlvl_config;
|
||||
unsigned char res21[0x8];
|
||||
unsigned int brbrsvconfig;
|
||||
unsigned int brbqosconfig;
|
||||
unsigned int membaseconfig0;
|
||||
unsigned int membaseconfig1;
|
||||
unsigned char res22[0xc];
|
||||
unsigned int wrlvl_config;
|
||||
unsigned char res23[0xc];
|
||||
unsigned int perevcontrol;
|
||||
unsigned int perev0config;
|
||||
unsigned int perev1config;
|
||||
unsigned int perev2config;
|
||||
unsigned int perev3config;
|
||||
unsigned char res24[0xdebc];
|
||||
unsigned int pmnc_ppc_a;
|
||||
unsigned char res25[0xc];
|
||||
unsigned int cntens_ppc_a;
|
||||
unsigned char res26[0xc];
|
||||
unsigned int cntenc_ppc_a;
|
||||
unsigned char res27[0xc];
|
||||
unsigned int intens_ppc_a;
|
||||
unsigned char res28[0xc];
|
||||
unsigned int intenc_ppc_a;
|
||||
unsigned char res29[0xc];
|
||||
unsigned int flag_ppc_a;
|
||||
unsigned char res30[0xac];
|
||||
unsigned int ccnt_ppc_a;
|
||||
unsigned char res31[0xc];
|
||||
unsigned int pmcnt0_ppc_a;
|
||||
unsigned char res32[0xc];
|
||||
unsigned int pmcnt1_ppc_a;
|
||||
unsigned char res33[0xc];
|
||||
unsigned int pmcnt2_ppc_a;
|
||||
unsigned char res34[0xc];
|
||||
unsigned int pmcnt3_ppc_a;
|
||||
};
|
||||
|
||||
struct exynos5_phy_control {
|
||||
unsigned int phy_con0;
|
||||
unsigned int phy_con1;
|
||||
unsigned int phy_con2;
|
||||
unsigned int phy_con3;
|
||||
unsigned int phy_con4;
|
||||
unsigned char res1[4];
|
||||
unsigned int phy_con6;
|
||||
unsigned char res2[4];
|
||||
unsigned int phy_con8;
|
||||
unsigned int phy_con9;
|
||||
unsigned int phy_con10;
|
||||
unsigned char res3[4];
|
||||
unsigned int phy_con12;
|
||||
unsigned int phy_con13;
|
||||
unsigned int phy_con14;
|
||||
unsigned int phy_con15;
|
||||
unsigned int phy_con16;
|
||||
unsigned char res4[4];
|
||||
unsigned int phy_con17;
|
||||
unsigned int phy_con18;
|
||||
unsigned int phy_con19;
|
||||
unsigned int phy_con20;
|
||||
unsigned int phy_con21;
|
||||
unsigned int phy_con22;
|
||||
unsigned int phy_con23;
|
||||
unsigned int phy_con24;
|
||||
unsigned int phy_con25;
|
||||
unsigned int phy_con26;
|
||||
unsigned int phy_con27;
|
||||
unsigned int phy_con28;
|
||||
unsigned int phy_con29;
|
||||
unsigned int phy_con30;
|
||||
unsigned int phy_con31;
|
||||
unsigned int phy_con32;
|
||||
unsigned int phy_con33;
|
||||
unsigned int phy_con34;
|
||||
unsigned int phy_con35;
|
||||
unsigned int phy_con36;
|
||||
unsigned int phy_con37;
|
||||
unsigned int phy_con38;
|
||||
unsigned int phy_con39;
|
||||
unsigned int phy_con40;
|
||||
unsigned int phy_con41;
|
||||
unsigned int phy_con42;
|
||||
};
|
||||
|
||||
enum ddr_mode {
|
||||
DDR_MODE_DDR2,
|
||||
DDR_MODE_DDR3,
|
||||
DDR_MODE_LPDDR2,
|
||||
DDR_MODE_LPDDR3,
|
||||
|
||||
DDR_MODE_COUNT,
|
||||
};
|
||||
|
||||
/* For reasons unknown, people are in the habit of taking a 32-bit
|
||||
* field with 2 possible values and packing it with, say, 2 bits. A
|
||||
* non-robust encoding, using only 2 bits of a 32-bit field, is
|
||||
* incredibly difficult to deal with when things go wrong, because
|
||||
* there are a lot of things that get expressed as 0, 1, or 2. If
|
||||
* you're scanning with jtag or dumping memory it is really hard to
|
||||
* tell when you've hit the beginning of the struct. So, let's be a
|
||||
* bit smart here. First, while it's common to let the enum count
|
||||
* entries for you, when there are two of them, we can do the
|
||||
* counting. And, let's set the values to something we can easily scan
|
||||
* for in memory. Since '1' and '2' are rather common, we pick
|
||||
* something that's actually of some value when things go wrong. This
|
||||
* setup motivated by a use case: something's going wrong and having a
|
||||
* manuf name of '1' or '2' is completely useless!
|
||||
*/
|
||||
enum mem_manuf {
|
||||
MEM_MANUF_AUTODETECT,
|
||||
MEM_MANUF_ELPIDA = 0xe7b1da,
|
||||
MEM_MANUF_SAMSUNG = 0x5a5096,
|
||||
|
||||
MEM_MANUF_COUNT = 2, // fancy that.
|
||||
};
|
||||
|
||||
enum {
|
||||
MEM_TIMINGS_MSR_COUNT = 4,
|
||||
};
|
||||
|
||||
#define DMC_INTERLEAVE_SIZE 0x1f
|
||||
|
||||
/* CONCONTROL register fields */
|
||||
#define CONCONTROL_DFI_INIT_START_SHIFT 28
|
||||
#define CONCONTROL_RD_FETCH_SHIFT 12
|
||||
#define CONCONTROL_RD_FETCH_MASK (0x7 << CONCONTROL_RD_FETCH_SHIFT)
|
||||
#define CONCONTROL_AREF_EN_SHIFT 5
|
||||
|
||||
/* PRECHCONFIG register field */
|
||||
#define PRECHCONFIG_TP_CNT_SHIFT 24
|
||||
|
||||
/* PWRDNCONFIG register field */
|
||||
#define PWRDNCONFIG_DPWRDN_CYC_SHIFT 0
|
||||
#define PWRDNCONFIG_DSREF_CYC_SHIFT 16
|
||||
|
||||
/* PHY_CON0 register fields */
|
||||
#define PHY_CON0_T_WRRDCMD_SHIFT 17
|
||||
#define PHY_CON0_T_WRRDCMD_MASK (0x7 << PHY_CON0_T_WRRDCMD_SHIFT)
|
||||
#define PHY_CON0_CTRL_DDR_MODE_SHIFT 11
|
||||
|
||||
/* PHY_CON1 register fields */
|
||||
#define PHY_CON1_RDLVL_RDDATA_ADJ_SHIFT 0
|
||||
|
||||
/* PHY_CON12 register fields */
|
||||
#define PHY_CON12_CTRL_START_POINT_SHIFT 24
|
||||
#define PHY_CON12_CTRL_INC_SHIFT 16
|
||||
#define PHY_CON12_CTRL_FORCE_SHIFT 8
|
||||
#define PHY_CON12_CTRL_START_SHIFT 6
|
||||
#define PHY_CON12_CTRL_START_MASK (1 << PHY_CON12_CTRL_START_SHIFT)
|
||||
#define PHY_CON12_CTRL_DLL_ON_SHIFT 5
|
||||
#define PHY_CON12_CTRL_DLL_ON_MASK (1 << PHY_CON12_CTRL_DLL_ON_SHIFT)
|
||||
#define PHY_CON12_CTRL_REF_SHIFT 1
|
||||
|
||||
/* PHY_CON16 register fields */
|
||||
#define PHY_CON16_ZQ_MODE_DDS_SHIFT 24
|
||||
#define PHY_CON16_ZQ_MODE_DDS_MASK (0x7 << PHY_CON16_ZQ_MODE_DDS_SHIFT)
|
||||
|
||||
#define PHY_CON16_ZQ_MODE_TERM_SHIFT 21
|
||||
#define PHY_CON16_ZQ_MODE_TERM_MASK (0x7 << PHY_CON16_ZQ_MODE_TERM_SHIFT)
|
||||
|
||||
#define PHY_CON16_ZQ_MODE_NOTERM_MASK (1 << 19)
|
||||
|
||||
/* PHY_CON42 register fields */
|
||||
#define PHY_CON42_CTRL_BSTLEN_SHIFT 8
|
||||
#define PHY_CON42_CTRL_BSTLEN_MASK (0xff << PHY_CON42_CTRL_BSTLEN_SHIFT)
|
||||
|
||||
#define PHY_CON42_CTRL_RDLAT_SHIFT 0
|
||||
#define PHY_CON42_CTRL_RDLAT_MASK (0x1f << PHY_CON42_CTRL_RDLAT_SHIFT)
|
||||
|
||||
/* These are the memory timings for a particular memory type and speed */
|
||||
struct mem_timings {
|
||||
enum mem_manuf mem_manuf; /* Memory manufacturer */
|
||||
enum ddr_mode mem_type; /* Memory type */
|
||||
unsigned int frequency_mhz; /* Frequency of memory in MHz */
|
||||
|
||||
/* Here follow the timing parameters for the selected memory */
|
||||
uint8_t apll_mdiv;
|
||||
uint8_t apll_pdiv;
|
||||
uint8_t apll_sdiv;
|
||||
uint8_t mpll_mdiv;
|
||||
uint8_t mpll_pdiv;
|
||||
uint8_t mpll_sdiv;
|
||||
uint8_t cpll_mdiv;
|
||||
uint8_t cpll_pdiv;
|
||||
uint8_t cpll_sdiv;
|
||||
uint8_t gpll_pdiv;
|
||||
uint16_t gpll_mdiv;
|
||||
uint8_t gpll_sdiv;
|
||||
uint8_t epll_mdiv;
|
||||
uint8_t epll_pdiv;
|
||||
uint8_t epll_sdiv;
|
||||
uint8_t vpll_mdiv;
|
||||
uint8_t vpll_pdiv;
|
||||
uint8_t vpll_sdiv;
|
||||
uint8_t bpll_mdiv;
|
||||
uint8_t bpll_pdiv;
|
||||
uint8_t bpll_sdiv;
|
||||
uint8_t use_bpll; /* 1 to use BPLL for cdrex, 0 to use MPLL */
|
||||
uint8_t pclk_cdrex_ratio;
|
||||
unsigned int direct_cmd_msr[MEM_TIMINGS_MSR_COUNT];
|
||||
|
||||
unsigned int timing_ref;
|
||||
unsigned int timing_row;
|
||||
unsigned int timing_data;
|
||||
unsigned int timing_power;
|
||||
|
||||
/* DQS, DQ, DEBUG offsets */
|
||||
unsigned int phy0_dqs;
|
||||
unsigned int phy1_dqs;
|
||||
unsigned int phy0_dq;
|
||||
unsigned int phy1_dq;
|
||||
uint8_t phy0_tFS;
|
||||
uint8_t phy1_tFS;
|
||||
uint8_t phy0_pulld_dqs;
|
||||
uint8_t phy1_pulld_dqs;
|
||||
|
||||
uint8_t lpddr3_ctrl_phy_reset;
|
||||
uint8_t ctrl_start_point;
|
||||
uint8_t ctrl_inc;
|
||||
uint8_t ctrl_start;
|
||||
uint8_t ctrl_dll_on;
|
||||
uint8_t ctrl_ref;
|
||||
|
||||
uint8_t ctrl_force;
|
||||
uint8_t ctrl_rdlat;
|
||||
uint8_t ctrl_bstlen;
|
||||
|
||||
uint8_t fp_resync;
|
||||
uint8_t iv_size;
|
||||
uint8_t dfi_init_start;
|
||||
uint8_t aref_en;
|
||||
|
||||
uint8_t rd_fetch;
|
||||
|
||||
uint8_t zq_mode_dds;
|
||||
uint8_t zq_mode_term;
|
||||
uint8_t zq_mode_noterm; /* 1 to allow termination disable */
|
||||
|
||||
unsigned int memcontrol;
|
||||
unsigned int memconfig;
|
||||
|
||||
unsigned int membaseconfig0;
|
||||
unsigned int membaseconfig1;
|
||||
unsigned int prechconfig_tp_cnt;
|
||||
unsigned int dpwrdn_cyc;
|
||||
unsigned int dsref_cyc;
|
||||
unsigned int concontrol;
|
||||
/* Channel and Chip Selection */
|
||||
uint8_t dmc_channels; /* number of memory channels */
|
||||
uint8_t chips_per_channel; /* number of chips per channel */
|
||||
uint8_t chips_to_configure; /* number of chips to configure */
|
||||
uint8_t send_zq_init; /* 1 to send this command */
|
||||
unsigned int impedance; /* drive strength impedeance */
|
||||
uint8_t gate_leveling_enable; /* check gate leveling is enabled */
|
||||
};
|
||||
|
||||
/**
|
||||
* Get the correct memory timings for our selected memory type and speed.
|
||||
*
|
||||
* @return pointer to the memory timings that we should use
|
||||
*/
|
||||
struct mem_timings *get_mem_timings(void);
|
||||
|
||||
#endif
|
||||
#endif
|
|
@ -0,0 +1,183 @@
|
|||
/*
|
||||
* This file is part of the coreboot project.
|
||||
*
|
||||
* Copyright (C) 2012 Samsung Electronics
|
||||
*
|
||||
* 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; version 2 of 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
/* Mem setup common file for different types of DDR present on SMDK5420 boards.
|
||||
*/
|
||||
|
||||
#include <console/console.h>
|
||||
#include <arch/io.h>
|
||||
#include <delay.h>
|
||||
#include "setup.h"
|
||||
#include "dmc.h"
|
||||
#include "clk.h"
|
||||
#include "setup.h"
|
||||
|
||||
#define ZQ_INIT_TIMEOUT 10000
|
||||
|
||||
int dmc_config_zq(struct mem_timings *mem,
|
||||
struct exynos5_phy_control *phy0_ctrl,
|
||||
struct exynos5_phy_control *phy1_ctrl)
|
||||
{
|
||||
unsigned long val = 0;
|
||||
int i;
|
||||
|
||||
/*
|
||||
* ZQ Calibration:
|
||||
* Select Driver Strength,
|
||||
* long calibration for manual calibration
|
||||
*/
|
||||
val = PHY_CON16_RESET_VAL;
|
||||
val |= mem->zq_mode_dds << PHY_CON16_ZQ_MODE_DDS_SHIFT;
|
||||
val |= mem->zq_mode_term << PHY_CON16_ZQ_MODE_TERM_SHIFT;
|
||||
val |= ZQ_CLK_DIV_EN;
|
||||
writel(val, &phy0_ctrl->phy_con16);
|
||||
writel(val, &phy1_ctrl->phy_con16);
|
||||
|
||||
/* Disable termination */
|
||||
if (mem->zq_mode_noterm)
|
||||
val |= PHY_CON16_ZQ_MODE_NOTERM_MASK;
|
||||
writel(val, &phy0_ctrl->phy_con16);
|
||||
writel(val, &phy1_ctrl->phy_con16);
|
||||
|
||||
/* ZQ_MANUAL_START: Enable */
|
||||
val |= ZQ_MANUAL_STR;
|
||||
writel(val, &phy0_ctrl->phy_con16);
|
||||
writel(val, &phy1_ctrl->phy_con16);
|
||||
|
||||
/* ZQ_MANUAL_START: Disable */
|
||||
val &= ~ZQ_MANUAL_STR;
|
||||
|
||||
/*
|
||||
* Since we are manaully calibrating the ZQ values,
|
||||
* we are looping for the ZQ_init to complete.
|
||||
*/
|
||||
i = ZQ_INIT_TIMEOUT;
|
||||
while ((readl(&phy0_ctrl->phy_con17) & ZQ_DONE) != ZQ_DONE && i > 0) {
|
||||
udelay(1);
|
||||
i--;
|
||||
}
|
||||
if (!i)
|
||||
return -1;
|
||||
writel(val, &phy0_ctrl->phy_con16);
|
||||
|
||||
i = ZQ_INIT_TIMEOUT;
|
||||
while ((readl(&phy1_ctrl->phy_con17) & ZQ_DONE) != ZQ_DONE && i > 0) {
|
||||
udelay(1);
|
||||
i--;
|
||||
}
|
||||
if (!i)
|
||||
return -1;
|
||||
writel(val, &phy1_ctrl->phy_con16);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void update_reset_dll(struct exynos5_dmc *dmc, enum ddr_mode mode)
|
||||
{
|
||||
unsigned long val;
|
||||
|
||||
if (mode == DDR_MODE_DDR3) {
|
||||
val = MEM_TERM_EN | PHY_TERM_EN | DMC_CTRL_SHGATE;
|
||||
writel(val, &dmc->phycontrol0);
|
||||
}
|
||||
|
||||
/* Update DLL Information: Force DLL Resyncronization */
|
||||
val = readl(&dmc->phycontrol0);
|
||||
val |= FP_RSYNC;
|
||||
writel(val, &dmc->phycontrol0);
|
||||
|
||||
/* Reset Force DLL Resyncronization */
|
||||
val = readl(&dmc->phycontrol0);
|
||||
val &= ~FP_RSYNC;
|
||||
writel(val, &dmc->phycontrol0);
|
||||
}
|
||||
|
||||
void dmc_config_mrs(struct mem_timings *mem, struct exynos5_dmc *dmc)
|
||||
{
|
||||
int channel, chip;
|
||||
|
||||
for (channel = 0; channel < mem->dmc_channels; channel++) {
|
||||
unsigned long mask;
|
||||
|
||||
mask = channel << DIRECT_CMD_CHANNEL_SHIFT;
|
||||
for (chip = 0; chip < mem->chips_to_configure; chip++) {
|
||||
int i;
|
||||
|
||||
mask |= chip << DIRECT_CMD_CHIP_SHIFT;
|
||||
|
||||
/* Sending NOP command */
|
||||
writel(DIRECT_CMD_NOP | mask, &dmc->directcmd);
|
||||
|
||||
/*
|
||||
* TODO(alim.akhtar@samsung.com): Do we need these
|
||||
* delays? This one and the next were not there for
|
||||
* DDR3.
|
||||
*/
|
||||
udelay(100);
|
||||
|
||||
/* Sending EMRS/MRS commands */
|
||||
for (i = 0; i < MEM_TIMINGS_MSR_COUNT; i++) {
|
||||
writel(mem->direct_cmd_msr[i] | mask,
|
||||
&dmc->directcmd);
|
||||
udelay(100);
|
||||
}
|
||||
|
||||
if (mem->send_zq_init) {
|
||||
/* Sending ZQINIT command */
|
||||
writel(DIRECT_CMD_ZQINIT | mask,
|
||||
&dmc->directcmd);
|
||||
/*
|
||||
* FIXME: This was originally sdelay(10000)
|
||||
* in the imported u-boot code. That may have
|
||||
* been meant to be sdelay(0x10000) since that
|
||||
* was used elsewhere in this function. Either
|
||||
* way seems to work, though.
|
||||
*/
|
||||
udelay(12);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void dmc_config_prech(struct mem_timings *mem, struct exynos5_dmc *dmc)
|
||||
{
|
||||
int channel, chip;
|
||||
|
||||
for (channel = 0; channel < mem->dmc_channels; channel++) {
|
||||
unsigned long mask;
|
||||
|
||||
mask = channel << DIRECT_CMD_CHANNEL_SHIFT;
|
||||
for (chip = 0; chip < mem->chips_per_channel; chip++) {
|
||||
mask |= chip << DIRECT_CMD_CHIP_SHIFT;
|
||||
|
||||
/* PALL (all banks precharge) CMD */
|
||||
writel(DIRECT_CMD_PALL | mask, &dmc->directcmd);
|
||||
udelay(100);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void dmc_config_memory(struct mem_timings *mem, struct exynos5_dmc *dmc)
|
||||
{
|
||||
writel(mem->memconfig, &dmc->memconfig0);
|
||||
writel(mem->memconfig, &dmc->memconfig1);
|
||||
writel(DMC_MEMBASECONFIG0_VAL, &dmc->membaseconfig0);
|
||||
writel(DMC_MEMBASECONFIG1_VAL, &dmc->membaseconfig1);
|
||||
}
|
||||
|
|
@ -0,0 +1,277 @@
|
|||
/*
|
||||
* This file is part of the coreboot project.
|
||||
*
|
||||
* Copyright (C) 2012 Samsung Electronics
|
||||
*
|
||||
* 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; version 2 of 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
/* DDR3 mem setup file for SMDK5420 board based on EXYNOS5 */
|
||||
|
||||
#include <console/console.h>
|
||||
#include <delay.h>
|
||||
#include <arch/io.h>
|
||||
#include "clk.h"
|
||||
#include "cpu.h"
|
||||
#include "dmc.h"
|
||||
#include "setup.h"
|
||||
|
||||
#define RDLVL_COMPLETE_TIMEOUT 10000
|
||||
|
||||
static void reset_phy_ctrl(void)
|
||||
{
|
||||
struct exynos5_clock *clk = (struct exynos5_clock *)EXYNOS5_CLOCK_BASE;
|
||||
|
||||
writel(LPDDR3PHY_CTRL_PHY_RESET_OFF, &clk->lpddr3phy_ctrl);
|
||||
writel(LPDDR3PHY_CTRL_PHY_RESET, &clk->lpddr3phy_ctrl);
|
||||
|
||||
#if 0
|
||||
/*
|
||||
* For proper memory initialization there should be a minimum delay of
|
||||
* 500us after the LPDDR3PHY_CTRL_PHY_RESET signal.
|
||||
* The below value is an approximate value whose calculation in done
|
||||
* considering that sdelay takes 2 instruction for every 1 delay cycle.
|
||||
* And assuming each instruction takes 1 clock cycle i.e 1/(1.7 Ghz)sec
|
||||
* So for 500 usec, the number of delay cycle should be
|
||||
* (500 * 10^-6) * (1.7 * 10^9) / 2 = 425000
|
||||
*
|
||||
* TODO(hatim.rv@samsung.com): Implement the delay using timer/counter
|
||||
*/
|
||||
sdelay(425000);
|
||||
#endif
|
||||
udelay(500);
|
||||
}
|
||||
|
||||
int ddr3_mem_ctrl_init(struct mem_timings *mem, unsigned long mem_iv_size,
|
||||
int mem_reset)
|
||||
{
|
||||
unsigned int val;
|
||||
struct exynos5_phy_control *phy0_ctrl, *phy1_ctrl;
|
||||
struct exynos5_dmc *dmc;
|
||||
int i;
|
||||
|
||||
phy0_ctrl = (struct exynos5_phy_control *)EXYNOS5_DMC_PHY0_BASE;
|
||||
phy1_ctrl = (struct exynos5_phy_control *)EXYNOS5_DMC_PHY1_BASE;
|
||||
dmc = (struct exynos5_dmc *)EXYNOS5_DMC_CTRL_BASE;
|
||||
|
||||
if (mem_reset) {
|
||||
printk(BIOS_SPEW, "%s: reset phy: ", __func__);
|
||||
reset_phy_ctrl();
|
||||
printk(BIOS_SPEW, "done\n");
|
||||
} else {
|
||||
printk(BIOS_SPEW, "%s: skip mem_reset.\n", __func__);
|
||||
}
|
||||
|
||||
/* Set Impedance Output Driver */
|
||||
printk(BIOS_SPEW, "ddr3_mem_ctrl_init: Set Impedance Output Driver\n");
|
||||
printk(BIOS_SPEW, "ddr3_mem_ctrl_init: mem->impedance 0x%x\n",
|
||||
mem->impedance);
|
||||
val = (mem->impedance << CA_CK_DRVR_DS_OFFSET) |
|
||||
(mem->impedance << CA_CKE_DRVR_DS_OFFSET) |
|
||||
(mem->impedance << CA_CS_DRVR_DS_OFFSET) |
|
||||
(mem->impedance << CA_ADR_DRVR_DS_OFFSET);
|
||||
printk(BIOS_SPEW, "ddr3_mem_ctrl_init: val 0x%x\n", val);
|
||||
writel(val, &phy0_ctrl->phy_con39);
|
||||
writel(val, &phy1_ctrl->phy_con39);
|
||||
|
||||
/* Set Read Latency and Burst Length for PHY0 and PHY1 */
|
||||
printk(BIOS_SPEW, "ddr3_mem_ctrl_init: "
|
||||
"Set Read Latency and Burst Length for PHY0 and PHY1\n");
|
||||
val = (mem->ctrl_bstlen << PHY_CON42_CTRL_BSTLEN_SHIFT) |
|
||||
(mem->ctrl_rdlat << PHY_CON42_CTRL_RDLAT_SHIFT);
|
||||
writel(val, &phy0_ctrl->phy_con42);
|
||||
writel(val, &phy1_ctrl->phy_con42);
|
||||
|
||||
/* ZQ Calibration */
|
||||
printk(BIOS_SPEW, "ddr3_mem_ctrl_init: ZQ Calibration\n");
|
||||
if (dmc_config_zq(mem, phy0_ctrl, phy1_ctrl))
|
||||
return SETUP_ERR_ZQ_CALIBRATION_FAILURE;
|
||||
|
||||
/* DQ Signal */
|
||||
printk(BIOS_SPEW, "ddr3_mem_ctrl_init: DQ Signal\n");
|
||||
writel(mem->phy0_pulld_dqs, &phy0_ctrl->phy_con14);
|
||||
writel(mem->phy1_pulld_dqs, &phy1_ctrl->phy_con14);
|
||||
|
||||
writel(mem->concontrol | (mem->rd_fetch << CONCONTROL_RD_FETCH_SHIFT)
|
||||
| (mem->dfi_init_start << CONCONTROL_DFI_INIT_START_SHIFT),
|
||||
&dmc->concontrol);
|
||||
|
||||
update_reset_dll(dmc, DDR_MODE_DDR3);
|
||||
|
||||
/* DQS Signal */
|
||||
printk(BIOS_SPEW, "ddr3_mem_ctrl_init: DQS Signal\n");
|
||||
writel(mem->phy0_dqs, &phy0_ctrl->phy_con4);
|
||||
writel(mem->phy1_dqs, &phy1_ctrl->phy_con4);
|
||||
|
||||
writel(mem->phy0_dq, &phy0_ctrl->phy_con6);
|
||||
writel(mem->phy1_dq, &phy1_ctrl->phy_con6);
|
||||
|
||||
writel(mem->phy0_tFS, &phy0_ctrl->phy_con10);
|
||||
writel(mem->phy1_tFS, &phy1_ctrl->phy_con10);
|
||||
|
||||
val = (mem->ctrl_start_point << PHY_CON12_CTRL_START_POINT_SHIFT) |
|
||||
(mem->ctrl_inc << PHY_CON12_CTRL_INC_SHIFT) |
|
||||
(mem->ctrl_dll_on << PHY_CON12_CTRL_DLL_ON_SHIFT) |
|
||||
(mem->ctrl_ref << PHY_CON12_CTRL_REF_SHIFT);
|
||||
writel(val, &phy0_ctrl->phy_con12);
|
||||
writel(val, &phy1_ctrl->phy_con12);
|
||||
|
||||
/* Start DLL locking */
|
||||
printk(BIOS_SPEW, "ddr3_mem_ctrl_init: Start DLL Locking\n");
|
||||
writel(val | (mem->ctrl_start << PHY_CON12_CTRL_START_SHIFT),
|
||||
&phy0_ctrl->phy_con12);
|
||||
writel(val | (mem->ctrl_start << PHY_CON12_CTRL_START_SHIFT),
|
||||
&phy1_ctrl->phy_con12);
|
||||
|
||||
update_reset_dll(dmc, DDR_MODE_DDR3);
|
||||
|
||||
writel(mem->concontrol | (mem->rd_fetch << CONCONTROL_RD_FETCH_SHIFT),
|
||||
&dmc->concontrol);
|
||||
|
||||
/* Memory Channel Inteleaving Size */
|
||||
printk(BIOS_SPEW, "ddr3_mem_ctrl_init: "
|
||||
"Memory Channel Inteleaving Size\n");
|
||||
writel(mem->iv_size, &dmc->ivcontrol);
|
||||
|
||||
/* Set DMC MEMCONTROL register */
|
||||
printk(BIOS_SPEW, "ddr3_mem_ctrl_init: Set DMC MEMCONTROL register\n");
|
||||
val = mem->memcontrol & ~DMC_MEMCONTROL_DSREF_ENABLE;
|
||||
writel(val, &dmc->memcontrol);
|
||||
|
||||
writel(mem->memconfig, &dmc->memconfig0);
|
||||
writel(mem->memconfig, &dmc->memconfig1);
|
||||
writel(mem->membaseconfig0, &dmc->membaseconfig0);
|
||||
writel(mem->membaseconfig1, &dmc->membaseconfig1);
|
||||
|
||||
/* Precharge Configuration */
|
||||
printk(BIOS_SPEW, "ddr3_mem_ctrl_init: Precharge Configuration\n");
|
||||
writel(mem->prechconfig_tp_cnt << PRECHCONFIG_TP_CNT_SHIFT,
|
||||
&dmc->prechconfig);
|
||||
|
||||
/* Power Down mode Configuration */
|
||||
printk(BIOS_SPEW, "ddr3_mem_ctrl_init: "
|
||||
"Power Down mode Configuraation\n");
|
||||
writel(mem->dpwrdn_cyc << PWRDNCONFIG_DPWRDN_CYC_SHIFT |
|
||||
mem->dsref_cyc << PWRDNCONFIG_DSREF_CYC_SHIFT,
|
||||
&dmc->pwrdnconfig);
|
||||
|
||||
/* TimingRow, TimingData, TimingPower and Timingaref
|
||||
* values as per Memory AC parameters
|
||||
*/
|
||||
printk(BIOS_SPEW, "ddr3_mem_ctrl_init: "
|
||||
"TimingRow, TimingData, TimingPower and Timingaref\n");
|
||||
writel(mem->timing_ref, &dmc->timingref);
|
||||
writel(mem->timing_row, &dmc->timingrow);
|
||||
writel(mem->timing_data, &dmc->timingdata);
|
||||
writel(mem->timing_power, &dmc->timingpower);
|
||||
|
||||
/* Send PALL command */
|
||||
printk(BIOS_SPEW, "ddr3_mem_ctrl_init: Send PALL Command\n");
|
||||
dmc_config_prech(mem, dmc);
|
||||
|
||||
/* Send NOP, MRS and ZQINIT commands */
|
||||
printk(BIOS_SPEW, "ddr3_mem_ctrl_init: Send NOP, MRS, and ZQINIT\n");
|
||||
dmc_config_mrs(mem, dmc);
|
||||
|
||||
if (mem->gate_leveling_enable) {
|
||||
val = PHY_CON0_RESET_VAL;
|
||||
val |= P0_CMD_EN;
|
||||
writel(val, &phy0_ctrl->phy_con0);
|
||||
writel(val, &phy1_ctrl->phy_con0);
|
||||
|
||||
val = PHY_CON2_RESET_VAL;
|
||||
val |= INIT_DESKEW_EN;
|
||||
writel(val, &phy0_ctrl->phy_con2);
|
||||
writel(val, &phy1_ctrl->phy_con2);
|
||||
|
||||
val = PHY_CON0_RESET_VAL;
|
||||
val |= P0_CMD_EN;
|
||||
val |= BYTE_RDLVL_EN;
|
||||
writel(val, &phy0_ctrl->phy_con0);
|
||||
writel(val, &phy1_ctrl->phy_con0);
|
||||
|
||||
val = (mem->ctrl_start_point <<
|
||||
PHY_CON12_CTRL_START_POINT_SHIFT) |
|
||||
(mem->ctrl_inc << PHY_CON12_CTRL_INC_SHIFT) |
|
||||
(mem->ctrl_force << PHY_CON12_CTRL_FORCE_SHIFT) |
|
||||
(mem->ctrl_start << PHY_CON12_CTRL_START_SHIFT) |
|
||||
(mem->ctrl_ref << PHY_CON12_CTRL_REF_SHIFT);
|
||||
writel(val, &phy0_ctrl->phy_con12);
|
||||
writel(val, &phy1_ctrl->phy_con12);
|
||||
|
||||
val = PHY_CON2_RESET_VAL;
|
||||
val |= INIT_DESKEW_EN;
|
||||
val |= RDLVL_GATE_EN;
|
||||
writel(val, &phy0_ctrl->phy_con2);
|
||||
writel(val, &phy1_ctrl->phy_con2);
|
||||
|
||||
val = PHY_CON0_RESET_VAL;
|
||||
val |= P0_CMD_EN;
|
||||
val |= BYTE_RDLVL_EN;
|
||||
val |= CTRL_SHGATE;
|
||||
writel(val, &phy0_ctrl->phy_con0);
|
||||
writel(val, &phy1_ctrl->phy_con0);
|
||||
|
||||
val = PHY_CON1_RESET_VAL;
|
||||
val &= ~(CTRL_GATEDURADJ_MASK);
|
||||
writel(val, &phy0_ctrl->phy_con1);
|
||||
writel(val, &phy1_ctrl->phy_con1);
|
||||
|
||||
writel(CTRL_RDLVL_GATE_ENABLE, &dmc->rdlvl_config);
|
||||
i = RDLVL_COMPLETE_TIMEOUT;
|
||||
while ((readl(&dmc->phystatus) &
|
||||
(RDLVL_COMPLETE_CHO | RDLVL_COMPLETE_CH1)) !=
|
||||
(RDLVL_COMPLETE_CHO | RDLVL_COMPLETE_CH1) && i > 0) {
|
||||
/*
|
||||
* TODO(waihong): Comment on how long this take to
|
||||
* timeout
|
||||
*/
|
||||
udelay(1);
|
||||
i--;
|
||||
}
|
||||
if (!i){
|
||||
printk(BIOS_SPEW, "Timeout on RDLVL. No DRAM.\n");
|
||||
return SETUP_ERR_RDLV_COMPLETE_TIMEOUT;
|
||||
}
|
||||
writel(CTRL_RDLVL_GATE_DISABLE, &dmc->rdlvl_config);
|
||||
|
||||
writel(0, &phy0_ctrl->phy_con14);
|
||||
writel(0, &phy1_ctrl->phy_con14);
|
||||
|
||||
val = (mem->ctrl_start_point <<
|
||||
PHY_CON12_CTRL_START_POINT_SHIFT) |
|
||||
(mem->ctrl_inc << PHY_CON12_CTRL_INC_SHIFT) |
|
||||
(mem->ctrl_force << PHY_CON12_CTRL_FORCE_SHIFT) |
|
||||
(mem->ctrl_start << PHY_CON12_CTRL_START_SHIFT) |
|
||||
(mem->ctrl_dll_on << PHY_CON12_CTRL_DLL_ON_SHIFT) |
|
||||
(mem->ctrl_ref << PHY_CON12_CTRL_REF_SHIFT);
|
||||
writel(val, &phy0_ctrl->phy_con12);
|
||||
writel(val, &phy1_ctrl->phy_con12);
|
||||
|
||||
update_reset_dll(dmc, DDR_MODE_DDR3);
|
||||
}
|
||||
|
||||
/* Send PALL command */
|
||||
printk(BIOS_SPEW, "ddr3_mem_ctrl_init: Send PALL Command\n");
|
||||
dmc_config_prech(mem, dmc);
|
||||
|
||||
writel(mem->memcontrol, &dmc->memcontrol);
|
||||
|
||||
/* Set DMC Concontrol and enable auto-refresh counter */
|
||||
printk(BIOS_SPEW, "ddr3_mem_ctrl_init: "
|
||||
"Set DMC Concontrol and enable auto-refresh counter\n");
|
||||
writel(mem->concontrol | (mem->rd_fetch << CONCONTROL_RD_FETCH_SHIFT)
|
||||
| (mem->aref_en << CONCONTROL_AREF_EN_SHIFT), &dmc->concontrol);
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,268 @@
|
|||
/*
|
||||
* This file is part of the coreboot project.
|
||||
*
|
||||
* Copyright 2013 Google Inc.
|
||||
* Copyright (C) 2012 Samsung Electronics
|
||||
*
|
||||
* 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; version 2 of 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
/* Header file for Samsung DP (Display Port) interface driver. */
|
||||
|
||||
#ifndef CPU_SAMSUNG_EXYNOS5420_DP_CORE_H
|
||||
#define CPU_SAMSUNG_EXYNOS5420_DP_CORE_H
|
||||
|
||||
#define STREAM_ON_TIMEOUT 100
|
||||
#define PLL_LOCK_TIMEOUT 10
|
||||
#define DP_INIT_TRIES 10
|
||||
#define MAX_CR_LOOP 5
|
||||
#define MAX_EQ_LOOP 4
|
||||
|
||||
/* Link tare type */
|
||||
enum link_rate {
|
||||
LINK_RATE_1_62GBPS = 0x06,
|
||||
LINK_RATE_2_70GBPS = 0x0a
|
||||
};
|
||||
|
||||
/* Number of lanes supported */
|
||||
enum link_lane_count {
|
||||
LANE_COUNT1 = 1,
|
||||
LANE_COUNT2 = 2,
|
||||
LANE_COUNT4 = 4
|
||||
};
|
||||
|
||||
/* Pre emphasis level */
|
||||
enum pre_emphasis_level {
|
||||
PRE_EMPHASIS_LEVEL_0,
|
||||
PRE_EMPHASIS_LEVEL_1,
|
||||
PRE_EMPHASIS_LEVEL_2,
|
||||
PRE_EMPHASIS_LEVEL_3,
|
||||
};
|
||||
|
||||
/* Type of color space */
|
||||
enum color_space {
|
||||
COLOR_RGB,
|
||||
COLOR_YCBCR422,
|
||||
COLOR_YCBCR444
|
||||
};
|
||||
|
||||
/* Video input Bit Per Color */
|
||||
enum color_depth {
|
||||
COLOR_6,
|
||||
COLOR_8,
|
||||
COLOR_10,
|
||||
COLOR_12
|
||||
};
|
||||
|
||||
/* Type of YCbCr coefficient */
|
||||
enum color_coefficient {
|
||||
COLOR_YCBCR601,
|
||||
COLOR_YCBCR709
|
||||
};
|
||||
|
||||
/* Color range */
|
||||
enum dynamic_range {
|
||||
VESA,
|
||||
CEA
|
||||
};
|
||||
|
||||
/* Status of PLL clock */
|
||||
enum pll_status {
|
||||
PLL_UNLOCKED,
|
||||
PLL_LOCKED
|
||||
};
|
||||
|
||||
/* To choose type of m_value */
|
||||
enum clock_recovery_m_value_type {
|
||||
CALCULATED_M,
|
||||
REGISTER_M
|
||||
};
|
||||
|
||||
struct video_info {
|
||||
enum color_space color_space;
|
||||
enum dynamic_range dynamic_range;
|
||||
enum color_coefficient ycbcr_coeff;
|
||||
enum color_depth color_depth;
|
||||
|
||||
enum link_rate link_rate;
|
||||
enum link_lane_count lane_count;
|
||||
|
||||
char *name;
|
||||
|
||||
unsigned int h_sync_polarity:1;
|
||||
unsigned int v_sync_polarity:1;
|
||||
unsigned int interlaced:1;
|
||||
};
|
||||
|
||||
struct link_train {
|
||||
u8 link_rate;
|
||||
u8 lane_count;
|
||||
};
|
||||
|
||||
struct s5p_dp_device {
|
||||
unsigned int irq;
|
||||
struct exynos5_dp *base;
|
||||
struct video_info *video_info;
|
||||
struct link_train link_train;
|
||||
};
|
||||
|
||||
/* this struct is used by mainboards to pass mode info to the driver */
|
||||
typedef struct vidinfo {
|
||||
u16 vl_col;
|
||||
u16 vl_row;
|
||||
u8 vl_bpix;
|
||||
u16 *cmap;
|
||||
} vidinfo_t;
|
||||
|
||||
/* s5p_dp_reg.c */
|
||||
|
||||
/*
|
||||
* Reset DP module
|
||||
*
|
||||
* param dp pointer to main s5p-dp structure
|
||||
*/
|
||||
void s5p_dp_reset(struct s5p_dp_device *dp);
|
||||
/*
|
||||
* Initialize DP to recieve video stream
|
||||
*
|
||||
* param dp pointer to main s5p-dp structure
|
||||
*/
|
||||
void s5p_dp_init_video(struct s5p_dp_device *dp);
|
||||
/*
|
||||
* Check whether PLL is locked
|
||||
*
|
||||
* param dp pointer to main s5p-dp structure
|
||||
* return Lock status
|
||||
*/
|
||||
unsigned int s5p_dp_get_pll_lock_status(struct s5p_dp_device *dp);
|
||||
/*
|
||||
* Initialize analog functions of DP
|
||||
*
|
||||
* param dp pointer to main s5p-dp structure
|
||||
* return 0 on success
|
||||
*/
|
||||
int s5p_dp_init_analog_func(struct s5p_dp_device *dp);
|
||||
/*
|
||||
* Initialize DP for AUX transaction
|
||||
*
|
||||
* param dp pointer to main s5p-dp structure
|
||||
*/
|
||||
void s5p_dp_init_aux(struct s5p_dp_device *dp);
|
||||
|
||||
/*
|
||||
* Start an AUX transaction.
|
||||
*
|
||||
* param dp pointer to main s5p-dp structure
|
||||
*/
|
||||
int s5p_dp_start_aux_transaction(struct s5p_dp_device *dp);
|
||||
|
||||
/*
|
||||
* Write a byte to DPCD register
|
||||
*
|
||||
* param dp pointer to main s5p-dp structure
|
||||
* param reg_addr DPCD register to be written
|
||||
* param data byte data to be written
|
||||
* return write status
|
||||
*/
|
||||
int s5p_dp_write_byte_to_dpcd(struct s5p_dp_device *dp,
|
||||
unsigned int reg_addr,
|
||||
unsigned char data);
|
||||
/*
|
||||
* Read a byte from DPCD register
|
||||
*
|
||||
* param dp pointer to main s5p-dp structure
|
||||
* param reg_addr DPCD register to read
|
||||
* param data read byte data
|
||||
* return read status
|
||||
*/
|
||||
int s5p_dp_read_byte_from_dpcd(struct s5p_dp_device *dp,
|
||||
unsigned int reg_addr,
|
||||
unsigned char *data);
|
||||
/*
|
||||
* Initialize DP video functions
|
||||
*
|
||||
* param dp pointer to main s5p-dp structure
|
||||
*/
|
||||
//void s5p_dp_init_video(struct s5p_dp_device *dp);
|
||||
|
||||
/*
|
||||
* Set color parameters for display
|
||||
*
|
||||
* param dp pointer to main s5p-dp structure
|
||||
* param color_depth Video input Bit Per Color
|
||||
* param color_space Colorimetric format of input video
|
||||
* param dynamic_range VESA range or CEA range
|
||||
* param coeff YCbCr Coefficients of input video
|
||||
*/
|
||||
void s5p_dp_set_video_color_format(struct s5p_dp_device *dp,
|
||||
unsigned int color_depth,
|
||||
unsigned int color_space,
|
||||
unsigned int dynamic_range,
|
||||
unsigned int coeff);
|
||||
/*
|
||||
* Check whether video clock is on
|
||||
*
|
||||
* param dp pointer to main s5p-dp structure
|
||||
* return clock status
|
||||
*/
|
||||
int s5p_dp_is_slave_video_stream_clock_on(struct s5p_dp_device *dp);
|
||||
/*
|
||||
* Check whether video clock is on
|
||||
*
|
||||
* param dp pointer to main s5p-dp structure
|
||||
* param type clock_recovery_m_value_type
|
||||
* param m_value to caluculate m_vid value
|
||||
* param n_value to caluculate n_vid value
|
||||
*/
|
||||
void s5p_dp_set_video_cr_mn(struct s5p_dp_device *dp,
|
||||
enum clock_recovery_m_value_type type,
|
||||
unsigned int m_value,
|
||||
unsigned int n_value);
|
||||
/*
|
||||
* Set DP to video slave mode thereby enabling video master
|
||||
*
|
||||
* param dp pointer to main s5p-dp structure
|
||||
*/
|
||||
void s5p_dp_enable_video_master(struct s5p_dp_device *dp);
|
||||
/*
|
||||
* Check whether video stream is on
|
||||
*
|
||||
* param dp pointer to main s5p-dp structure
|
||||
* return video stream status
|
||||
*/
|
||||
int s5p_dp_is_video_stream_on(struct s5p_dp_device *dp);
|
||||
/*
|
||||
* Configure DP in slave mode
|
||||
*
|
||||
* param dp pointer to main s5p-dp structure
|
||||
* param video_info pointer to main video_info structure.
|
||||
*/
|
||||
void s5p_dp_config_video_slave_mode(struct s5p_dp_device *dp,
|
||||
struct video_info *video_info);
|
||||
|
||||
/*
|
||||
* Wait unitl HW link training done
|
||||
*
|
||||
* param dp pointer to main s5p-dp structure
|
||||
*/
|
||||
void s5p_dp_wait_hw_link_training_done(struct s5p_dp_device *dp);
|
||||
|
||||
/* startup and init */
|
||||
struct exynos5_fimd_panel;
|
||||
void fb_init(vidinfo_t *panel_info, void *lcdbase,
|
||||
struct exynos5_fimd_panel *pd);
|
||||
int dp_controller_init(struct s5p_dp_device *dp_device);
|
||||
int lcd_ctrl_init(vidinfo_t *panel_info,
|
||||
struct exynos5_fimd_panel *panel_data, void *lcdbase);
|
||||
#endif /* CPU_SAMSUNG_EXYNOS5420_DP_CORE_H */
|
|
@ -0,0 +1,495 @@
|
|||
/*
|
||||
* This file is part of the coreboot project.
|
||||
*
|
||||
* Copyright (C) 2012 Samsung Electronics
|
||||
*
|
||||
* 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; version 2 of 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
/* Samsung DP (Display port) register interface driver. */
|
||||
|
||||
#include <console/console.h>
|
||||
#include <arch/io.h>
|
||||
#include <delay.h>
|
||||
#include "timer.h"
|
||||
#include "clk.h"
|
||||
#include "cpu.h"
|
||||
#include "periph.h"
|
||||
#include "dp.h"
|
||||
#include "fimd.h"
|
||||
#include "dp-core.h"
|
||||
|
||||
void s5p_dp_reset(struct s5p_dp_device *dp)
|
||||
{
|
||||
u32 reg;
|
||||
struct exynos5_dp *base = dp->base;
|
||||
|
||||
writel(RESET_DP_TX, &base->dp_tx_sw_reset);
|
||||
|
||||
/* Stop Video */
|
||||
clrbits_le32(&base->video_ctl_1, VIDEO_EN);
|
||||
clrbits_le32(&base->video_ctl_1, HDCP_VIDEO_MUTE);
|
||||
|
||||
reg = MASTER_VID_FUNC_EN_N | SLAVE_VID_FUNC_EN_N |
|
||||
AUD_FIFO_FUNC_EN_N | AUD_FUNC_EN_N |
|
||||
HDCP_FUNC_EN_N | SW_FUNC_EN_N;
|
||||
writel(reg, &base->func_en_1);
|
||||
|
||||
reg = SSC_FUNC_EN_N | AUX_FUNC_EN_N |
|
||||
SERDES_FIFO_FUNC_EN_N |
|
||||
LS_CLK_DOMAIN_FUNC_EN_N;
|
||||
writel(reg, &base->func_en_2);
|
||||
|
||||
udelay(20);
|
||||
|
||||
reg = LANE3_MAP_LOGIC_LANE_3 | LANE2_MAP_LOGIC_LANE_2 |
|
||||
LANE1_MAP_LOGIC_LANE_1 | LANE0_MAP_LOGIC_LANE_0;
|
||||
|
||||
writel(reg, &base->lane_map);
|
||||
|
||||
writel(0x0, &base->sys_ctl_1);
|
||||
writel(0x40, &base->sys_ctl_2);
|
||||
writel(0x0, &base->sys_ctl_3);
|
||||
writel(0x0, &base->sys_ctl_4);
|
||||
|
||||
writel(0x0, &base->pkt_send_ctl);
|
||||
writel(0x0, &base->dp_hdcp_ctl);
|
||||
|
||||
writel(0x5e, &base->dp_hpd_deglitch_l);
|
||||
writel(0x1a, &base->dp_hpd_deglitch_h);
|
||||
|
||||
writel(0x10, &base->dp_debug_ctl);
|
||||
|
||||
writel(0x0, &base->dp_phy_test);
|
||||
|
||||
writel(0x0, &base->dp_video_fifo_thrd);
|
||||
writel(0x20, &base->dp_audio_margin);
|
||||
|
||||
writel(0x4, &base->m_vid_gen_filter_th);
|
||||
writel(0x2, &base->m_aud_gen_filter_th);
|
||||
|
||||
writel(0x00000101, &base->soc_general_ctl);
|
||||
|
||||
/* Set Analog Parameters */
|
||||
writel(0x10, &base->analog_ctl_1);
|
||||
writel(0x0C, &base->analog_ctl_2);
|
||||
writel(0x85, &base->analog_ctl_3);
|
||||
writel(0x66, &base->pll_filter_ctl_1);
|
||||
writel(0x0, &base->tx_amp_tuning_ctl);
|
||||
|
||||
/* Set interrupt pin assertion polarity as high */
|
||||
writel(INT_POL0 | INT_POL1, &base->int_ctl);
|
||||
|
||||
/* Clear pending regisers */
|
||||
writel(0xff, &base->common_int_sta_1);
|
||||
writel(0x4f, &base->common_int_sta_2);
|
||||
writel(0xe0, &base->common_int_sta_3);
|
||||
writel(0xe7, &base->common_int_sta_4);
|
||||
writel(0x63, &base->dp_int_sta);
|
||||
|
||||
/* 0:mask,1: unmask */
|
||||
writel(0x00, &base->common_int_mask_1);
|
||||
writel(0x00, &base->common_int_mask_2);
|
||||
writel(0x00, &base->common_int_mask_3);
|
||||
writel(0x00, &base->common_int_mask_4);
|
||||
writel(0x00, &base->int_sta_mask);
|
||||
}
|
||||
|
||||
unsigned int s5p_dp_get_pll_lock_status(struct s5p_dp_device *dp)
|
||||
{
|
||||
u32 reg;
|
||||
|
||||
reg = readl(&dp->base->dp_debug_ctl);
|
||||
if (reg & PLL_LOCK)
|
||||
return PLL_LOCKED;
|
||||
else
|
||||
return PLL_UNLOCKED;
|
||||
}
|
||||
|
||||
int s5p_dp_init_analog_func(struct s5p_dp_device *dp)
|
||||
{
|
||||
u32 reg;
|
||||
u32 start;
|
||||
struct exynos5_dp *base = dp->base;
|
||||
|
||||
writel(0x00, &base->dp_phy_pd);
|
||||
|
||||
reg = PLL_LOCK_CHG;
|
||||
writel(reg, &base->common_int_sta_1);
|
||||
|
||||
clrbits_le32(&base->dp_debug_ctl, (F_PLL_LOCK | PLL_LOCK_CTRL));
|
||||
|
||||
/* Power up PLL */
|
||||
if (s5p_dp_get_pll_lock_status(dp) == PLL_UNLOCKED) {
|
||||
|
||||
clrbits_le32(&base->dp_pll_ctl, DP_PLL_PD);
|
||||
|
||||
start = get_timer(0);
|
||||
while (s5p_dp_get_pll_lock_status(dp) == PLL_UNLOCKED) {
|
||||
if (get_timer(start) > PLL_LOCK_TIMEOUT) {
|
||||
printk(BIOS_ERR, "%s: PLL is not locked\n",
|
||||
__func__);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Enable Serdes FIFO function and Link symbol clock domain module */
|
||||
clrbits_le32(&base->func_en_2, (SERDES_FIFO_FUNC_EN_N |
|
||||
LS_CLK_DOMAIN_FUNC_EN_N | AUX_FUNC_EN_N));
|
||||
return 0;
|
||||
}
|
||||
|
||||
void s5p_dp_init_aux(struct s5p_dp_device *dp)
|
||||
{
|
||||
u32 reg;
|
||||
struct exynos5_dp *base = dp->base;
|
||||
|
||||
/* Clear inerrupts related to AUX channel */
|
||||
reg = RPLY_RECEIV | AUX_ERR;
|
||||
writel(reg, &base->dp_int_sta);
|
||||
|
||||
/* Disable AUX channel module */
|
||||
setbits_le32(&base->func_en_2, AUX_FUNC_EN_N);
|
||||
|
||||
/* Disable AUX transaction H/W retry */
|
||||
reg = (3 & AUX_BIT_PERIOD_MASK) << AUX_BIT_PERIOD_SHIFT;
|
||||
reg |= (0 & AUX_HW_RETRY_COUNT_MASK) << AUX_HW_RETRY_COUNT_SHIFT;
|
||||
reg |= (AUX_HW_RETRY_INTERVAL_600_US << AUX_HW_RETRY_INTERVAL_SHIFT);
|
||||
writel(reg, &base->aux_hw_retry_ctl) ;
|
||||
|
||||
/* Receive AUX Channel DEFER commands equal to DEFFER_COUNT*64 */
|
||||
reg = DEFER_CTRL_EN;
|
||||
reg |= (1 & DEFER_COUNT_MASK) << DEFER_COUNT_SHIFT;
|
||||
writel(reg, &base->aux_ch_defer_dtl);
|
||||
|
||||
/* Enable AUX channel module */
|
||||
clrbits_le32(&base->func_en_2, AUX_FUNC_EN_N);
|
||||
}
|
||||
|
||||
int s5p_dp_start_aux_transaction(struct s5p_dp_device *dp)
|
||||
{
|
||||
int reg;
|
||||
struct exynos5_dp *base = dp->base;
|
||||
|
||||
/* Enable AUX CH operation */
|
||||
setbits_le32(&base->aux_ch_ctl_2, AUX_EN);
|
||||
|
||||
/* Is AUX CH command reply received? */
|
||||
reg = readl(&base->dp_int_sta);
|
||||
while (!(reg & RPLY_RECEIV))
|
||||
reg = readl(&base->dp_int_sta);
|
||||
|
||||
/* Clear interrupt source for AUX CH command reply */
|
||||
writel(RPLY_RECEIV, &base->dp_int_sta);
|
||||
|
||||
/* Clear interrupt source for AUX CH access error */
|
||||
reg = readl(&base->dp_int_sta);
|
||||
if (reg & AUX_ERR) {
|
||||
printk(BIOS_ERR, "%s: AUX_ERR encountered, dp_int_sta: "
|
||||
"0x%02x\n", __func__, reg);
|
||||
writel(AUX_ERR, &base->dp_int_sta);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Check AUX CH error access status */
|
||||
reg = readl(&base->dp_int_sta);
|
||||
if ((reg & AUX_STATUS_MASK) != 0) {
|
||||
printk(BIOS_ERR, "AUX CH error happens: %d\n\n",
|
||||
reg & AUX_STATUS_MASK);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int s5p_dp_write_byte_to_dpcd(struct s5p_dp_device *dp,
|
||||
unsigned int reg_addr,
|
||||
unsigned char data)
|
||||
{
|
||||
u32 reg;
|
||||
int i;
|
||||
int retval;
|
||||
struct exynos5_dp *base = dp->base;
|
||||
|
||||
for (i = 0; i < MAX_AUX_RETRY_COUNT; i++) {
|
||||
/* Clear AUX CH data buffer */
|
||||
writel(BUF_CLR, &base->buf_data_ctl);
|
||||
|
||||
/* Select DPCD device address */
|
||||
reg = reg_addr >> AUX_ADDR_7_0_SHIFT;
|
||||
reg &= AUX_ADDR_7_0_MASK;
|
||||
writel(reg, &base->aux_addr_7_0);
|
||||
reg = reg_addr >> AUX_ADDR_15_8_SHIFT;
|
||||
reg &= AUX_ADDR_15_8_MASK;
|
||||
writel(reg, &base->aux_addr_15_8);
|
||||
reg = reg_addr >> AUX_ADDR_19_16_SHIFT;
|
||||
reg &= AUX_ADDR_19_16_MASK;
|
||||
writel(reg, &base->aux_addr_19_16);
|
||||
|
||||
/* Write data buffer */
|
||||
reg = (unsigned int)data;
|
||||
writel(reg, &base->buf_data_0);
|
||||
|
||||
/*
|
||||
* Set DisplayPort transaction and write 1 byte
|
||||
* If bit 3 is 1, DisplayPort transaction.
|
||||
* If Bit 3 is 0, I2C transaction.
|
||||
*/
|
||||
reg = AUX_TX_COMM_DP_TRANSACTION | AUX_TX_COMM_WRITE;
|
||||
writel(reg, &base->aux_ch_ctl_1);
|
||||
|
||||
/* Start AUX transaction */
|
||||
retval = s5p_dp_start_aux_transaction(dp);
|
||||
if (retval == 0)
|
||||
break;
|
||||
else
|
||||
printk(BIOS_DEBUG, "Aux Transaction fail!\n");
|
||||
}
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
int s5p_dp_read_byte_from_dpcd(struct s5p_dp_device *dp,
|
||||
unsigned int reg_addr,
|
||||
unsigned char *data)
|
||||
{
|
||||
u32 reg;
|
||||
int i;
|
||||
int retval;
|
||||
struct exynos5_dp *base = dp->base;
|
||||
|
||||
for (i = 0; i < MAX_AUX_RETRY_COUNT; i++) {
|
||||
/* Clear AUX CH data buffer */
|
||||
writel(BUF_CLR, &base->buf_data_ctl);
|
||||
|
||||
/* Select DPCD device address */
|
||||
reg = reg_addr >> AUX_ADDR_7_0_SHIFT;
|
||||
reg &= AUX_ADDR_7_0_MASK;
|
||||
writel(reg, &base->aux_addr_7_0);
|
||||
reg = reg_addr >> AUX_ADDR_15_8_SHIFT;
|
||||
reg &= AUX_ADDR_15_8_MASK;
|
||||
writel(reg, &base->aux_addr_15_8);
|
||||
reg = reg_addr >> AUX_ADDR_19_16_SHIFT;
|
||||
reg &= AUX_ADDR_19_16_MASK;
|
||||
writel(reg, &base->aux_addr_19_16);
|
||||
|
||||
/*
|
||||
* Set DisplayPort transaction and read 1 byte
|
||||
* If bit 3 is 1, DisplayPort transaction.
|
||||
* If Bit 3 is 0, I2C transaction.
|
||||
*/
|
||||
reg = AUX_TX_COMM_DP_TRANSACTION | AUX_TX_COMM_READ;
|
||||
writel(reg, &base->aux_ch_ctl_1);
|
||||
|
||||
/* Start AUX transaction */
|
||||
retval = s5p_dp_start_aux_transaction(dp);
|
||||
if (retval == 0)
|
||||
break;
|
||||
else
|
||||
printk(BIOS_DEBUG, "Aux Transaction fail!\n");
|
||||
}
|
||||
|
||||
/* Read data buffer */
|
||||
if (!retval) {
|
||||
reg = readl(&base->buf_data_0);
|
||||
*data = (unsigned char)(reg & 0xff);
|
||||
}
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
void s5p_dp_init_video(struct s5p_dp_device *dp)
|
||||
{
|
||||
u32 reg;
|
||||
struct exynos5_dp *base = dp->base;
|
||||
|
||||
reg = VSYNC_DET | VID_FORMAT_CHG | VID_CLK_CHG;
|
||||
writel(reg, &base->common_int_sta_1);
|
||||
|
||||
reg = 0x0;
|
||||
writel(reg, &base->sys_ctl_1);
|
||||
|
||||
reg = (4 & CHA_CRI_MASK) << CHA_CRI_SHIFT;
|
||||
reg |= CHA_CTRL;
|
||||
writel(reg, &base->sys_ctl_2);
|
||||
|
||||
reg = 0x0;
|
||||
writel(reg, &base->sys_ctl_3);
|
||||
}
|
||||
|
||||
void s5p_dp_set_video_color_format(struct s5p_dp_device *dp,
|
||||
unsigned int color_depth,
|
||||
unsigned int color_space,
|
||||
unsigned int dynamic_range,
|
||||
unsigned int coeff)
|
||||
{
|
||||
u32 reg;
|
||||
struct exynos5_dp *base = dp->base;
|
||||
|
||||
/* Configure the input color depth, color space, dynamic range */
|
||||
reg = (dynamic_range << IN_D_RANGE_SHIFT) |
|
||||
(color_depth << IN_BPC_SHIFT) |
|
||||
(color_space << IN_COLOR_F_SHIFT);
|
||||
writel(reg, &base->video_ctl_2);
|
||||
|
||||
/* Set Input Color YCbCr Coefficients to ITU601 or ITU709 */
|
||||
reg = readl(&base->video_ctl_3);
|
||||
reg &= ~IN_YC_COEFFI_MASK;
|
||||
if (coeff)
|
||||
reg |= IN_YC_COEFFI_ITU709;
|
||||
else
|
||||
reg |= IN_YC_COEFFI_ITU601;
|
||||
writel(reg, &base->video_ctl_3);
|
||||
}
|
||||
|
||||
int s5p_dp_is_slave_video_stream_clock_on(struct s5p_dp_device *dp)
|
||||
{
|
||||
u32 reg;
|
||||
struct exynos5_dp *base = dp->base;
|
||||
|
||||
reg = readl(&base->sys_ctl_1);
|
||||
writel(reg, &base->sys_ctl_1);
|
||||
|
||||
reg = readl(&base->sys_ctl_1);
|
||||
|
||||
if (!(reg & DET_STA))
|
||||
return -1;
|
||||
|
||||
reg = readl(&base->sys_ctl_2);
|
||||
writel(reg, &base->sys_ctl_2);
|
||||
|
||||
reg = readl(&base->sys_ctl_2);
|
||||
|
||||
if (reg & CHA_STA) {
|
||||
printk(BIOS_DEBUG, "Input stream clk is changing\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void s5p_dp_set_video_cr_mn(struct s5p_dp_device *dp,
|
||||
enum clock_recovery_m_value_type type,
|
||||
unsigned int m_value,
|
||||
unsigned int n_value)
|
||||
{
|
||||
u32 reg;
|
||||
struct exynos5_dp *base = dp->base;
|
||||
|
||||
if (type == REGISTER_M) {
|
||||
setbits_le32(&base->sys_ctl_4, FIX_M_VID);
|
||||
|
||||
reg = m_value >> M_VID_0_VALUE_SHIFT;
|
||||
writel(reg, &base->m_vid_0);
|
||||
|
||||
reg = (m_value >> M_VID_1_VALUE_SHIFT);
|
||||
writel(reg, &base->m_vid_1);
|
||||
|
||||
reg = (m_value >> M_VID_2_VALUE_SHIFT);
|
||||
writel(reg, &base->m_vid_2);
|
||||
|
||||
reg = n_value >> N_VID_0_VALUE_SHIFT;
|
||||
writel(reg, &base->n_vid_0);
|
||||
|
||||
reg = (n_value >> N_VID_1_VALUE_SHIFT);
|
||||
writel(reg, &base->n_vid_1);
|
||||
|
||||
reg = (n_value >> N_VID_2_VALUE_SHIFT);
|
||||
writel(reg, &base->n_vid_2);
|
||||
} else {
|
||||
clrbits_le32(&base->sys_ctl_4, FIX_M_VID);
|
||||
|
||||
writel(0x00, &base->n_vid_0);
|
||||
writel(0x80, &base->n_vid_1);
|
||||
writel(0x00, &base->n_vid_2);
|
||||
}
|
||||
}
|
||||
|
||||
void s5p_dp_enable_video_master(struct s5p_dp_device *dp)
|
||||
{
|
||||
u32 reg;
|
||||
struct exynos5_dp *base = dp->base;
|
||||
|
||||
reg = readl(&base->soc_general_ctl);
|
||||
reg &= ~VIDEO_MODE_MASK;
|
||||
reg |= VIDEO_MODE_SLAVE_MODE;
|
||||
writel(reg, &base->soc_general_ctl);
|
||||
}
|
||||
|
||||
int s5p_dp_is_video_stream_on(struct s5p_dp_device *dp)
|
||||
{
|
||||
u32 reg, i = 0;
|
||||
u32 start;
|
||||
struct exynos5_dp *base = dp->base;
|
||||
|
||||
/* Wait for 4 VSYNC_DET interrupts */
|
||||
start = get_timer(0);
|
||||
do {
|
||||
reg = readl(&base->common_int_sta_1);
|
||||
if (reg & VSYNC_DET) {
|
||||
i++;
|
||||
writel(reg | VSYNC_DET, &base->common_int_sta_1);
|
||||
}
|
||||
if (i == 4)
|
||||
break;
|
||||
} while (get_timer(start) <= STREAM_ON_TIMEOUT);
|
||||
|
||||
if (i != 4) {
|
||||
printk(BIOS_DEBUG, "s5p_dp_is_video_stream_on timeout\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void s5p_dp_config_video_slave_mode(struct s5p_dp_device *dp,
|
||||
struct video_info *video_info)
|
||||
{
|
||||
u32 reg;
|
||||
struct exynos5_dp *base = dp->base;
|
||||
|
||||
reg = readl(&base->func_en_1);
|
||||
reg &= ~(MASTER_VID_FUNC_EN_N|SLAVE_VID_FUNC_EN_N);
|
||||
reg |= MASTER_VID_FUNC_EN_N;
|
||||
writel(reg, &base->func_en_1);
|
||||
|
||||
reg = readl(&base->video_ctl_10);
|
||||
reg &= ~INTERACE_SCAN_CFG;
|
||||
reg |= (video_info->interlaced << 2);
|
||||
writel(reg, &base->video_ctl_10);
|
||||
|
||||
reg = readl(&base->video_ctl_10);
|
||||
reg &= ~VSYNC_POLARITY_CFG;
|
||||
reg |= (video_info->v_sync_polarity << 1);
|
||||
writel(reg, &base->video_ctl_10);
|
||||
|
||||
reg = readl(&base->video_ctl_10);
|
||||
reg &= ~HSYNC_POLARITY_CFG;
|
||||
reg |= (video_info->h_sync_polarity << 0);
|
||||
writel(reg, &base->video_ctl_10);
|
||||
|
||||
reg = AUDIO_MODE_SPDIF_MODE | VIDEO_MODE_SLAVE_MODE;
|
||||
writel(reg, &base->soc_general_ctl);
|
||||
}
|
||||
|
||||
void s5p_dp_wait_hw_link_training_done(struct s5p_dp_device *dp)
|
||||
{
|
||||
u32 reg;
|
||||
struct exynos5_dp *base = dp->base;
|
||||
|
||||
reg = readl(&base->dp_hw_link_training);
|
||||
while (reg & HW_TRAINING_EN)
|
||||
reg = readl(&base->dp_hw_link_training);
|
||||
}
|
|
@ -0,0 +1,497 @@
|
|||
/*
|
||||
* This file is part of the coreboot project.
|
||||
*
|
||||
* Copyright 2013 Google Inc.
|
||||
* Copyright (C) 2012 Samsung Electronics
|
||||
*
|
||||
* 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; version 2 of 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
/* Register map for Exynos5 DP */
|
||||
|
||||
#ifndef CPU_SAMSUNG_EXYNOS5420_DP_H
|
||||
#define CPU_SAMSUNG_EXYNOS5420_DP_H
|
||||
|
||||
/* DSIM register map */
|
||||
struct exynos5_dp {
|
||||
u8 res1[0x10];
|
||||
u32 dp_tx_version;
|
||||
u32 dp_tx_sw_reset;
|
||||
u32 func_en_1;
|
||||
u32 func_en_2;
|
||||
u32 video_ctl_1;
|
||||
u32 video_ctl_2;
|
||||
u32 video_ctl_3;
|
||||
u32 video_ctl_4;
|
||||
u32 clr_blue_cb;
|
||||
u32 clr_green_y;
|
||||
u32 clr_red_cr;
|
||||
u32 video_ctl_8;
|
||||
u8 res2[0x4];
|
||||
u32 video_ctl_10;
|
||||
u32 total_line_l;
|
||||
u32 total_line_h;
|
||||
u32 active_line_l;
|
||||
u32 active_line_h;
|
||||
u32 v_f_porch;
|
||||
u32 vsync;
|
||||
u32 v_b_porch;
|
||||
u32 total_pixel_l;
|
||||
u32 total_pixel_h;
|
||||
u32 active_pixel_l;
|
||||
u32 active_pixel_h;
|
||||
u32 h_f_porch_l;
|
||||
u32 h_f_porch_h;
|
||||
u32 hsync_l;
|
||||
u32 hysnc_h;
|
||||
u32 h_b_porch_l;
|
||||
u32 h_b_porch_h;
|
||||
u32 vid_status;
|
||||
u32 total_line_sta_l;
|
||||
u32 total_line_sta_h;
|
||||
u32 active_line_sta_l;
|
||||
u32 active_line_sta_h;
|
||||
u32 v_f_porch_sta;
|
||||
u32 vsync_sta;
|
||||
u32 v_b_porch_sta;
|
||||
u32 total_pixel_sta_l;
|
||||
u32 total_pixel_sta_h;
|
||||
u32 active_pixel_sta_l;
|
||||
u32 active_pixel_sta_h;
|
||||
u32 h_f_porch_sta_l;
|
||||
u32 h_f_porch_sta_h;
|
||||
u32 hsync_sta_l;
|
||||
u32 hsync_sta_h;
|
||||
u32 h_b_porch_sta_l;
|
||||
u32 h_b_porch__sta_h;
|
||||
u8 res3[0x288];
|
||||
u32 lane_map;
|
||||
u8 res4[0x10];
|
||||
u32 analog_ctl_1;
|
||||
u32 analog_ctl_2;
|
||||
u32 analog_ctl_3;
|
||||
u32 pll_filter_ctl_1;
|
||||
u32 tx_amp_tuning_ctl;
|
||||
u8 res5[0xc];
|
||||
u32 aux_hw_retry_ctl;
|
||||
u8 res6[0x2c];
|
||||
u32 int_state;
|
||||
u32 common_int_sta_1;
|
||||
u32 common_int_sta_2;
|
||||
u32 common_int_sta_3;
|
||||
u32 common_int_sta_4;
|
||||
u8 res7[0x8];
|
||||
u32 dp_int_sta;
|
||||
u32 common_int_mask_1;
|
||||
u32 common_int_mask_2;
|
||||
u32 common_int_mask_3;
|
||||
u32 common_int_mask_4;
|
||||
u8 res8[0x08];
|
||||
u32 int_sta_mask;
|
||||
u32 int_ctl;
|
||||
u8 res9[0x200];
|
||||
u32 sys_ctl_1;
|
||||
u32 sys_ctl_2;
|
||||
u32 sys_ctl_3;
|
||||
u32 sys_ctl_4;
|
||||
u32 dp_vid_ctl;
|
||||
u8 res10[0x2c];
|
||||
u32 pkt_send_ctl;
|
||||
u8 res11[0x4];
|
||||
u32 dp_hdcp_ctl;
|
||||
u8 res12[0x34];
|
||||
u32 link_bw_set;
|
||||
u32 lane_count_set;
|
||||
u32 dp_training_ptn_set;
|
||||
u32 ln0_link_trn_ctl;
|
||||
u32 ln1_link_trn_ctl;
|
||||
u32 ln2_link_trn_ctl;
|
||||
u32 ln3_link_trn_ctl;
|
||||
u32 dp_dn_spread;
|
||||
u32 dp_hw_link_training;
|
||||
u8 res13[0x1c];
|
||||
u32 dp_debug_ctl;
|
||||
u32 dp_hpd_deglitch_l;
|
||||
u32 dp_hpd_deglitch_h;
|
||||
u8 res14[0x14];
|
||||
u32 dp_link_debug_ctl;
|
||||
u8 res15[0x1c];
|
||||
u32 m_vid_0;
|
||||
u32 m_vid_1;
|
||||
u32 m_vid_2;
|
||||
u32 n_vid_0;
|
||||
u32 n_vid_1;
|
||||
u32 n_vid_2;
|
||||
u32 m_vid_mon;
|
||||
u32 dp_pll_ctl;
|
||||
u32 dp_phy_pd;
|
||||
u32 dp_phy_test;
|
||||
u8 res16[0x8];
|
||||
u32 dp_video_fifo_thrd;
|
||||
u8 res17[0x8];
|
||||
u32 dp_audio_margin;
|
||||
u32 dp_dn_spread_ctl_1;
|
||||
u32 dp_dn_spread_ctl_2;
|
||||
u8 res18[0x18];
|
||||
u32 dp_m_cal_ctl;
|
||||
u32 m_vid_gen_filter_th;
|
||||
u8 res19[0x14];
|
||||
u32 m_aud_gen_filter_th;
|
||||
u32 aux_ch_sta;
|
||||
u32 aux_err_num;
|
||||
u32 aux_ch_defer_dtl;
|
||||
u32 aux_rx_comm;
|
||||
u32 buf_data_ctl;
|
||||
u32 aux_ch_ctl_1;
|
||||
u32 aux_addr_7_0;
|
||||
u32 aux_addr_15_8;
|
||||
u32 aux_addr_19_16;
|
||||
u32 aux_ch_ctl_2;
|
||||
u8 res20[0x18];
|
||||
u32 buf_data_0;
|
||||
u8 res21[0x3c];
|
||||
u32 soc_general_ctl;
|
||||
};
|
||||
/* DP_TX_SW_RESET */
|
||||
#define RESET_DP_TX (1 << 0)
|
||||
|
||||
/* DP_FUNC_EN_1 */
|
||||
#define MASTER_VID_FUNC_EN_N (1 << 7)
|
||||
#define SLAVE_VID_FUNC_EN_N (1 << 5)
|
||||
#define AUD_FIFO_FUNC_EN_N (1 << 4)
|
||||
#define AUD_FUNC_EN_N (1 << 3)
|
||||
#define HDCP_FUNC_EN_N (1 << 2)
|
||||
#define CRC_FUNC_EN_N (1 << 1)
|
||||
#define SW_FUNC_EN_N (1 << 0)
|
||||
|
||||
/* DP_FUNC_EN_2 */
|
||||
#define SSC_FUNC_EN_N (1 << 7)
|
||||
#define AUX_FUNC_EN_N (1 << 2)
|
||||
#define SERDES_FIFO_FUNC_EN_N (1 << 1)
|
||||
#define LS_CLK_DOMAIN_FUNC_EN_N (1 << 0)
|
||||
|
||||
/* DP_VIDEO_CTL_1 */
|
||||
#define VIDEO_EN (1 << 7)
|
||||
#define HDCP_VIDEO_MUTE (1 << 6)
|
||||
|
||||
/* DP_VIDEO_CTL_1 */
|
||||
#define IN_D_RANGE_MASK (1 << 7)
|
||||
#define IN_D_RANGE_SHIFT (7)
|
||||
#define IN_D_RANGE_CEA (1 << 7)
|
||||
#define IN_D_RANGE_VESA (0 << 7)
|
||||
#define IN_BPC_MASK (7 << 4)
|
||||
#define IN_BPC_SHIFT (4)
|
||||
#define IN_BPC_12_BITS (3 << 4)
|
||||
#define IN_BPC_10_BITS (2 << 4)
|
||||
#define IN_BPC_8_BITS (1 << 4)
|
||||
#define IN_BPC_6_BITS (0 << 4)
|
||||
#define IN_COLOR_F_MASK (3 << 0)
|
||||
#define IN_COLOR_F_SHIFT (0)
|
||||
#define IN_COLOR_F_YCBCR444 (2 << 0)
|
||||
#define IN_COLOR_F_YCBCR422 (1 << 0)
|
||||
#define IN_COLOR_F_RGB (0 << 0)
|
||||
|
||||
/* DP_VIDEO_CTL_3 */
|
||||
#define IN_YC_COEFFI_MASK (1 << 7)
|
||||
#define IN_YC_COEFFI_SHIFT (7)
|
||||
#define IN_YC_COEFFI_ITU709 (1 << 7)
|
||||
#define IN_YC_COEFFI_ITU601 (0 << 7)
|
||||
#define VID_CHK_UPDATE_TYPE_MASK (1 << 4)
|
||||
#define VID_CHK_UPDATE_TYPE_SHIFT (4)
|
||||
#define VID_CHK_UPDATE_TYPE_1 (1 << 4)
|
||||
#define VID_CHK_UPDATE_TYPE_0 (0 << 4)
|
||||
|
||||
/* DP_VIDEO_CTL_10 */
|
||||
#define FORMAT_SEL (1 << 4)
|
||||
#define INTERACE_SCAN_CFG (1 << 2)
|
||||
#define VSYNC_POLARITY_CFG (1 << 1)
|
||||
#define HSYNC_POLARITY_CFG (1 << 0)
|
||||
|
||||
/* DP_LANE_MAP */
|
||||
#define LANE3_MAP_LOGIC_LANE_0 (0 << 6)
|
||||
#define LANE3_MAP_LOGIC_LANE_1 (1 << 6)
|
||||
#define LANE3_MAP_LOGIC_LANE_2 (2 << 6)
|
||||
#define LANE3_MAP_LOGIC_LANE_3 (3 << 6)
|
||||
#define LANE2_MAP_LOGIC_LANE_0 (0 << 4)
|
||||
#define LANE2_MAP_LOGIC_LANE_1 (1 << 4)
|
||||
#define LANE2_MAP_LOGIC_LANE_2 (2 << 4)
|
||||
#define LANE2_MAP_LOGIC_LANE_3 (3 << 4)
|
||||
#define LANE1_MAP_LOGIC_LANE_0 (0 << 2)
|
||||
#define LANE1_MAP_LOGIC_LANE_1 (1 << 2)
|
||||
#define LANE1_MAP_LOGIC_LANE_2 (2 << 2)
|
||||
#define LANE1_MAP_LOGIC_LANE_3 (3 << 2)
|
||||
#define LANE0_MAP_LOGIC_LANE_0 (0 << 0)
|
||||
#define LANE0_MAP_LOGIC_LANE_1 (1 << 0)
|
||||
#define LANE0_MAP_LOGIC_LANE_2 (2 << 0)
|
||||
#define LANE0_MAP_LOGIC_LANE_3 (3 << 0)
|
||||
|
||||
/* DP_AUX_HW_RETRY_CTL */
|
||||
#define AUX_BIT_PERIOD_SHIFT 8
|
||||
#define AUX_BIT_PERIOD_MASK 7
|
||||
|
||||
#define AUX_HW_RETRY_INTERVAL_SHIFT 3
|
||||
#define AUX_HW_RETRY_INTERVAL_600_US 0
|
||||
#define AUX_HW_RETRY_INTERVAL_800_US 1
|
||||
#define AUX_HW_RETRY_INTERVAL_1000_US 2
|
||||
#define AUX_HW_RETRY_INTERVAL_1800_US 3
|
||||
#define AUX_HW_RETRY_COUNT_SHIFT 0
|
||||
#define AUX_HW_RETRY_COUNT_MASK 7
|
||||
|
||||
/* DP_COMMON_INT_STA_1 */
|
||||
#define VSYNC_DET (1 << 7)
|
||||
#define PLL_LOCK_CHG (1 << 6)
|
||||
#define SPDIF_ERR (1 << 5)
|
||||
#define SPDIF_UNSTBL (1 << 4)
|
||||
#define VID_FORMAT_CHG (1 << 3)
|
||||
#define AUD_CLK_CHG (1 << 2)
|
||||
#define VID_CLK_CHG (1 << 1)
|
||||
#define SW_INT (1 << 0)
|
||||
|
||||
/* DP_COMMON_INT_STA_2 */
|
||||
#define ENC_EN_CHG (1 << 6)
|
||||
#define HW_BKSV_RDY (1 << 3)
|
||||
#define HW_SHA_DONE (1 << 2)
|
||||
#define HW_AUTH_STATE_CHG (1 << 1)
|
||||
#define HW_AUTH_DONE (1 << 0)
|
||||
|
||||
/* DP_COMMON_INT_STA_3 */
|
||||
#define AFIFO_UNDER (1 << 7)
|
||||
#define AFIFO_OVER (1 << 6)
|
||||
#define R0_CHK_FLAG (1 << 5)
|
||||
|
||||
/* DP_COMMON_INT_STA_4 */
|
||||
#define PSR_ACTIVE (1 << 7)
|
||||
#define PSR_INACTIVE (1 << 6)
|
||||
#define SPDIF_BI_PHASE_ERR (1 << 5)
|
||||
#define HOTPLUG_CHG (1 << 2)
|
||||
#define HPD_LOST (1 << 1)
|
||||
#define PLUG (1 << 0)
|
||||
|
||||
/* DP_INT_STA */
|
||||
#define INT_HPD (1 << 6)
|
||||
#define HW_TRAINING_FINISH (1 << 5)
|
||||
#define RPLY_RECEIV (1 << 1)
|
||||
#define AUX_ERR (1 << 0)
|
||||
|
||||
/* DP_INT_CTL */
|
||||
#define INT_POL0 (1 << 0)
|
||||
#define INT_POL1 (1 << 1)
|
||||
#define SOFT_INT_CTRL (1 << 2)
|
||||
|
||||
/* DP_SYS_CTL_1 */
|
||||
#define DET_STA (1 << 2)
|
||||
#define FORCE_DET (1 << 1)
|
||||
#define DET_CTRL (1 << 0)
|
||||
|
||||
/* DP_SYS_CTL_2 */
|
||||
#define CHA_CRI_SHIFT 4
|
||||
#define CHA_CRI_MASK 0xf
|
||||
#define CHA_STA (1 << 2)
|
||||
#define FORCE_CHA (1 << 1)
|
||||
#define CHA_CTRL (1 << 0)
|
||||
|
||||
/* DP_SYS_CTL_3 */
|
||||
#define HPD_STATUS (1 << 6)
|
||||
#define F_HPD (1 << 5)
|
||||
#define HPD_CTRL (1 << 4)
|
||||
#define HDCP_RDY (1 << 3)
|
||||
#define STRM_VALID (1 << 2)
|
||||
#define F_VALID (1 << 1)
|
||||
#define VALID_CTRL (1 << 0)
|
||||
|
||||
/* DP_SYS_CTL_4 */
|
||||
#define FIX_M_AUD (1 << 4)
|
||||
#define ENHANCED (1 << 3)
|
||||
#define FIX_M_VID (1 << 2)
|
||||
#define M_VID_UPDATE_CTRL (3 << 0)
|
||||
|
||||
/* DP_TRAINING_PTN_SET */
|
||||
#define SCRAMBLER_TYPE (1 << 9)
|
||||
#define HW_LINK_TRAINING_PATTERN (1 << 8)
|
||||
#define SCRAMBLING_DISABLE (1 << 5)
|
||||
#define SCRAMBLING_ENABLE (0 << 5)
|
||||
#define LINK_QUAL_PATTERN_SET_MASK (3 << 2)
|
||||
#define LINK_QUAL_PATTERN_SET_PRBS7 (3 << 2)
|
||||
#define LINK_QUAL_PATTERN_SET_D10_2 (1 << 2)
|
||||
#define LINK_QUAL_PATTERN_SET_DISABLE (0 << 2)
|
||||
#define SW_TRAINING_PATTERN_SET_MASK (3 << 0)
|
||||
#define SW_TRAINING_PATTERN_SET_PTN2 (2 << 0)
|
||||
#define SW_TRAINING_PATTERN_SET_PTN1 (1 << 0)
|
||||
#define SW_TRAINING_PATTERN_SET_NORMAL (0 << 0)
|
||||
|
||||
/* DP_LN0_LINK_TRAINING_CTL */
|
||||
#define PRE_EMPHASIS_SET_SHIFT (3)
|
||||
|
||||
/* DP_DEBUG_CTL */
|
||||
#define PLL_LOCK (1 << 4)
|
||||
#define F_PLL_LOCK (1 << 3)
|
||||
#define PLL_LOCK_CTRL (1 << 2)
|
||||
#define PN_INV (1 << 0)
|
||||
|
||||
/* DP_M_VID */
|
||||
#define M_VID_0_VALUE_SHIFT 0
|
||||
#define M_VID_1_VALUE_SHIFT 8
|
||||
#define M_VID_2_VALUE_SHIFT 16
|
||||
|
||||
/* DP_M_VID */
|
||||
#define N_VID_0_VALUE_SHIFT 0
|
||||
#define N_VID_1_VALUE_SHIFT 8
|
||||
#define N_VID_2_VALUE_SHIFT 16
|
||||
|
||||
/* DP_PLL_CTL */
|
||||
#define DP_PLL_PD (1 << 7)
|
||||
#define DP_PLL_RESET (1 << 6)
|
||||
#define DP_PLL_LOOP_BIT_DEFAULT (1 << 4)
|
||||
#define DP_PLL_REF_BIT_1_1250V (5 << 0)
|
||||
#define DP_PLL_REF_BIT_1_2500V (7 << 0)
|
||||
|
||||
/* DP_PHY_PD */
|
||||
#define DP_PHY_PD (1 << 5)
|
||||
#define AUX_PD (1 << 4)
|
||||
#define CH3_PD (1 << 3)
|
||||
#define CH2_PD (1 << 2)
|
||||
#define CH1_PD (1 << 1)
|
||||
#define CH0_PD (1 << 0)
|
||||
|
||||
/* DP_PHY_TEST */
|
||||
#define MACRO_RST (1 << 5)
|
||||
#define CH1_TEST (1 << 1)
|
||||
#define CH0_TEST (1 << 0)
|
||||
|
||||
/* DP_AUX_CH_STA */
|
||||
#define AUX_BUSY (1 << 4)
|
||||
#define AUX_STATUS_MASK (0xf << 0)
|
||||
|
||||
/* DP_AUX_CH_DEFER_CTL */
|
||||
#define DEFER_CTRL_EN (1 << 7)
|
||||
#define DEFER_COUNT_SHIFT 0
|
||||
#define DEFER_COUNT_MASK 0x7f
|
||||
|
||||
/* DP_AUX_RX_COMM */
|
||||
#define AUX_RX_COMM_I2C_DEFER (2 << 2)
|
||||
#define AUX_RX_COMM_AUX_DEFER (2 << 0)
|
||||
|
||||
/* DP_BUFFER_DATA_CTL */
|
||||
#define BUF_CLR (1 << 7)
|
||||
|
||||
/* Maximum number of tries for Aux Transaction */
|
||||
#define MAX_AUX_RETRY_COUNT 10
|
||||
|
||||
/* DP_AUX_CH_CTL_1 */
|
||||
#define AUX_LENGTH_SHIFT 4
|
||||
#define AUX_LENGTH_MASK 0xf
|
||||
|
||||
#define AUX_TX_COMM_MASK (0xf << 0)
|
||||
#define AUX_TX_COMM_DP_TRANSACTION (1 << 3)
|
||||
#define AUX_TX_COMM_I2C_TRANSACTION (0 << 3)
|
||||
#define AUX_TX_COMM_MOT (1 << 2)
|
||||
#define AUX_TX_COMM_WRITE (0 << 0)
|
||||
#define AUX_TX_COMM_READ (1 << 0)
|
||||
|
||||
/* DP_AUX_ADDR_7_0 */
|
||||
#define AUX_ADDR_7_0_SHIFT 0
|
||||
#define AUX_ADDR_7_0_MASK 0xff
|
||||
|
||||
/* DP_AUX_ADDR_15_8 */
|
||||
#define AUX_ADDR_15_8_SHIFT 8
|
||||
#define AUX_ADDR_15_8_MASK 0xff
|
||||
|
||||
/* DP_AUX_ADDR_19_16 */
|
||||
#define AUX_ADDR_19_16_SHIFT 16
|
||||
#define AUX_ADDR_19_16_MASK 0x0f
|
||||
|
||||
/* DP_AUX_CH_CTL_2 */
|
||||
#define ADDR_ONLY (1 << 1)
|
||||
#define AUX_EN (1 << 0)
|
||||
|
||||
/* DP_SOC_GENERAL_CTL */
|
||||
#define AUDIO_MODE_SPDIF_MODE (1 << 8)
|
||||
#define AUDIO_MODE_MASTER_MODE (0 << 8)
|
||||
#define MASTER_VIDEO_INTERLACE_EN (1 << 4)
|
||||
#define VIDEO_MASTER_CLK_SEL (1 << 2)
|
||||
#define VIDEO_MASTER_MODE_EN (1 << 1)
|
||||
#define VIDEO_MODE_MASK (1 << 0)
|
||||
#define VIDEO_MODE_SLAVE_MODE (1 << 0)
|
||||
#define VIDEO_MODE_MASTER_MODE (0 << 0)
|
||||
|
||||
#define HW_TRAINING_ERROR_CODE (7<<4)
|
||||
#define HW_TRAINING_EN (1<<0)
|
||||
|
||||
/* I2C EDID Chip ID, Slave Address */
|
||||
#define I2C_EDID_DEVICE_ADDR 0x50
|
||||
#define I2C_E_EDID_DEVICE_ADDR 0x30
|
||||
|
||||
#define EDID_BLOCK_LENGTH 0x80
|
||||
#define EDID_HEADER_PATTERN 0x00
|
||||
#define EDID_EXTENSION_FLAG 0x7e
|
||||
#define EDID_CHECKSUM 0x7f
|
||||
|
||||
/* Definition for DPCD Register */
|
||||
#define DPCD_ADDR_DPCD_REV 0x0000
|
||||
#define DPCD_ADDR_MAX_LINK_RATE 0x0001
|
||||
#define DPCD_ADDR_MAX_LANE_COUNT 0x0002
|
||||
#define DPCD_ADDR_LINK_BW_SET 0x0100
|
||||
#define DPCD_ADDR_LANE_COUNT_SET 0x0101
|
||||
#define DPCD_ADDR_TRAINING_PATTERN_SET 0x0102
|
||||
#define DPCD_ADDR_TRAINING_LANE0_SET 0x0103
|
||||
#define DPCD_ADDR_LANE0_1_STATUS 0x0202
|
||||
#define DPCD_ADDR_LANE_ALIGN__STATUS_UPDATED 0x0204
|
||||
#define DPCD_ADDR_ADJUST_REQUEST_LANE0_1 0x0206
|
||||
#define DPCD_ADDR_ADJUST_REQUEST_LANE2_3 0x0207
|
||||
#define DPCD_ADDR_TEST_REQUEST 0x0218
|
||||
#define DPCD_ADDR_TEST_RESPONSE 0x0260
|
||||
#define DPCD_ADDR_TEST_EDID_CHECKSUM 0x0261
|
||||
#define DPCD_ADDR_SINK_POWER_STATE 0x0600
|
||||
|
||||
/* DPCD_ADDR_MAX_LANE_COUNT */
|
||||
#define DPCD_MAX_LANE_COUNT_MASK 0x1f
|
||||
|
||||
/* DPCD_ADDR_LANE_COUNT_SET */
|
||||
#define DPCD_ENHANCED_FRAME_EN (1 << 7)
|
||||
#define DPCD_LANE_COUNT_SET_MASK 0x1f
|
||||
|
||||
/* DPCD_ADDR_TRAINING_PATTERN_SET */
|
||||
#define DPCD_SCRAMBLING_DISABLED (1 << 5)
|
||||
#define DPCD_SCRAMBLING_ENABLED (0 << 5)
|
||||
#define DPCD_TRAINING_PATTERN_2 (2 << 0)
|
||||
#define DPCD_TRAINING_PATTERN_1 (1 << 0)
|
||||
#define DPCD_TRAINING_PATTERN_DISABLED (0 << 0)
|
||||
|
||||
/* DPCD_ADDR_LANE0_1_STATUS */
|
||||
#define DPCD_LANE_SYMBOL_LOCKED (1 << 2)
|
||||
#define DPCD_LANE_CHANNEL_EQ_DONE (1 << 1)
|
||||
#define DPCD_LANE_CR_DONE (1 << 0)
|
||||
#define DPCD_CHANNEL_EQ_BITS (DPCD_LANE_CR_DONE | \
|
||||
DPCD_LANE_CHANNEL_EQ_DONE | \
|
||||
DPCD_LANE_SYMBOL_LOCKED)
|
||||
|
||||
/* DPCD_ADDR_LANE_ALIGN__STATUS_UPDATED */
|
||||
#define DPCD_LINK_STATUS_UPDATED (1 << 7)
|
||||
#define DPCD_DOWNSTREAM_PORT_STATUS_CHANGED (1 << 6)
|
||||
#define DPCD_INTERLANE_ALIGN_DONE (1 << 0)
|
||||
|
||||
/* DPCD_ADDR_TEST_REQUEST */
|
||||
#define DPCD_TEST_EDID_READ (1 << 2)
|
||||
|
||||
/* DPCD_ADDR_TEST_RESPONSE */
|
||||
#define DPCD_TEST_EDID_CHECKSUM_WRITE (1 << 2)
|
||||
|
||||
/* DPCD_ADDR_SINK_POWER_STATE */
|
||||
#define DPCD_SET_POWER_STATE_D0 (1 << 0)
|
||||
#define DPCD_SET_POWER_STATE_D4 (2 << 0)
|
||||
|
||||
/* Allow DP Gating clock and set FIMD source to 267 Mhz for DP */
|
||||
void clock_init_dp_clock(void);
|
||||
|
||||
#endif
|
|
@ -0,0 +1,109 @@
|
|||
/*
|
||||
* This file is part of the coreboot project.
|
||||
*
|
||||
* Copyright (C) 2012 Samsung Electronics
|
||||
*
|
||||
* 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; version 2 of 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
/* Register map for Exynos5 MIPI-DSIM */
|
||||
|
||||
#ifndef CPU_SAMSUNG_EXYNOS5420_DSIM_H
|
||||
#define CPU_SAMSUNG_EXYNOS5420_DSIM_H
|
||||
|
||||
/* DSIM register map */
|
||||
struct exynos5_dsim {
|
||||
unsigned int status;
|
||||
unsigned int swrst;
|
||||
unsigned int clkctrl;
|
||||
unsigned int timeout;
|
||||
unsigned int config;
|
||||
unsigned int escmode;
|
||||
unsigned int mdresol;
|
||||
unsigned int mvporch;
|
||||
unsigned int mhporch;
|
||||
unsigned int msync;
|
||||
unsigned int sdresol;
|
||||
unsigned int intsrc;
|
||||
unsigned int intmsk;
|
||||
unsigned int pkthdr;
|
||||
unsigned int payload;
|
||||
unsigned int rxfifo;
|
||||
unsigned int res1;
|
||||
unsigned int fifoctrl;
|
||||
unsigned int res2;
|
||||
unsigned int pllctrl;
|
||||
unsigned int plltmr;
|
||||
unsigned int phyacchr;
|
||||
unsigned int phyacchr1;
|
||||
};
|
||||
|
||||
#define ENABLE 1
|
||||
#define DISABLE 0
|
||||
|
||||
#define DSIM_SWRST (1 << 0)
|
||||
#define NUM_OF_DAT_LANE_IS_FOUR (3 << 5)
|
||||
#define DATA_LANE_0_EN (1 << 0)
|
||||
#define DATA_LANE_1_EN (1 << 1)
|
||||
#define DATA_LANE_2_EN (1 << 2)
|
||||
#define DATA_LANE_3_EN (1 << 3)
|
||||
#define CLK_LANE_EN (1 << 4)
|
||||
#define ENABLE_ALL_DATA_LANE DATA_LANE_0_EN | \
|
||||
DATA_LANE_1_EN | \
|
||||
DATA_LANE_2_EN | \
|
||||
DATA_LANE_3_EN
|
||||
#define MAIN_PIX_FORMAT_OFFSET 12
|
||||
#define RGB_565_16_BIT 0x4
|
||||
#define VIDEO_MODE (1 << 25)
|
||||
#define BURST_MODE (1 << 26)
|
||||
|
||||
|
||||
#define DSIM_PHYACCHR_AFC_EN (1 << 14)
|
||||
#define DSIM_PHYACCHR_AFC_CTL_OFFSET 5
|
||||
|
||||
#define DSIM_PLLCTRL_PMS_OFFSET 1
|
||||
#define DSIM_FREQ_BAND_OFFSET 24
|
||||
|
||||
#define LANE_ESC_CLK_EN_ALL (0x1f << 19)
|
||||
#define BYTE_CLK_EN (1 << 24)
|
||||
#define DSIM_ESC_CLK_EN (1 << 28)
|
||||
#define TXREQUEST_HS_CLK_ON (1 << 31)
|
||||
|
||||
#define LP_MODE_ENABLE (1 << 7)
|
||||
#define STOP_STATE_CNT_OFFSET 21
|
||||
|
||||
#define MAIN_VBP_OFFSET 0
|
||||
#define STABLE_VFP_OFFSET 16
|
||||
#define CMD_ALLOW_OFFSET 28
|
||||
|
||||
#define MAIN_HBP_OFFSET 0
|
||||
#define MAIN_HFP_OFFSET 16
|
||||
|
||||
#define MAIN_HSA_OFFSET 0
|
||||
#define MAIN_VSA_OFFSET 22
|
||||
|
||||
#define MAIN_STANDBY (1 << 31)
|
||||
#define MAIN_VRESOL_OFFSET 16
|
||||
#define MAIN_HRESOL_OFFSET 0
|
||||
|
||||
#define SFR_FIFO_EMPTY (1 << 29)
|
||||
|
||||
#define DSIM_PLL_EN_SHIFT (1 << 23)
|
||||
#define PLL_STABLE (1 << 31)
|
||||
|
||||
#define DSIM_STOP_STATE_DAT(x) (((x) & 0xf) << 0)
|
||||
#define DSIM_STOP_STATE_CLK (1 << 8)
|
||||
#define DSIM_TX_READY_HS_CLK (1 << 10)
|
||||
|
||||
#endif
|
|
@ -0,0 +1,597 @@
|
|||
/*
|
||||
* This file is part of the coreboot project.
|
||||
*
|
||||
* Copyright 2013 Google Inc.
|
||||
* Copyright (C) 2012 Samsung Electronics
|
||||
*
|
||||
* 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; version 2 of 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
/* LCD driver for Exynos */
|
||||
|
||||
#include <arch/io.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <timer.h>
|
||||
#include <delay.h>
|
||||
#include <console/console.h>
|
||||
#include "timer.h"
|
||||
#include "cpu.h"
|
||||
#include "power.h"
|
||||
#include "sysreg.h"
|
||||
#include <drivers/maxim/max77686/max77686.h>
|
||||
|
||||
#include "device/i2c.h"
|
||||
#include "i2c.h"
|
||||
#include "fimd.h"
|
||||
#include "dp.h"
|
||||
#include "dp-core.h"
|
||||
|
||||
/*
|
||||
* Here is the rough outline of how we bring up the display:
|
||||
* 1. Upon power-on Sink generates a hot plug detection pulse thru HPD
|
||||
* 2. Source determines video mode by reading DPCD receiver capability field
|
||||
* (DPCD 00000h to 0000Dh) including eDP CP capability register (DPCD
|
||||
* 0000Dh).
|
||||
* 3. Sink replies DPCD receiver capability field.
|
||||
* 4. Source starts EDID read thru I2C-over-AUX.
|
||||
* 5. Sink replies EDID thru I2C-over-AUX.
|
||||
* 6. Source determines link configuration, such as MAX_LINK_RATE and
|
||||
* MAX_LANE_COUNT. Source also determines which type of eDP Authentication
|
||||
* method to use and writes DPCD link configuration field (DPCD 00100h to
|
||||
* 0010Ah) including eDP configuration set (DPCD 0010Ah).
|
||||
* 7. Source starts link training. Sink does clock recovery and equalization.
|
||||
* 8. Source reads DPCD link status field (DPCD 00200h to 0020Bh).
|
||||
* 9. Sink replies DPCD link status field. If main link is not stable, Source
|
||||
* repeats Step 7.
|
||||
* 10. Source sends MSA (Main Stream Attribute) data. Sink extracts video
|
||||
* parameters and recovers stream clock.
|
||||
* 11. Source sends video data.
|
||||
*/
|
||||
|
||||
/* To help debug any init errors here, define a list of possible errors */
|
||||
enum {
|
||||
ERR_PLL_NOT_UNLOCKED = 2,
|
||||
ERR_VIDEO_CLOCK_BAD,
|
||||
ERR_VIDEO_STREAM_BAD,
|
||||
ERR_DPCD_READ_ERROR1, /* 5 */
|
||||
|
||||
ERR_DPCD_WRITE_ERROR1,
|
||||
ERR_DPCD_READ_ERROR2,
|
||||
ERR_DPCD_WRITE_ERROR2,
|
||||
ERR_INVALID_LANE,
|
||||
ERR_PLL_NOT_LOCKED, /* 10 */
|
||||
|
||||
ERR_PRE_EMPHASIS_LEVELS,
|
||||
ERR_LINK_RATE_ABNORMAL,
|
||||
ERR_MAX_LANE_COUNT_ABNORMAL,
|
||||
ERR_LINK_TRAINING_FAILURE,
|
||||
ERR_MISSING_DP_BASE, /* 15 */
|
||||
|
||||
ERR_NO_FDT_NODE,
|
||||
};
|
||||
/* ok, this is stupid, but we're going to leave the variables in here until we
|
||||
* know it works. One cleanup task at a time.
|
||||
*/
|
||||
enum stage_t {
|
||||
STAGE_START = 0,
|
||||
STAGE_LCD_VDD,
|
||||
STAGE_BRIDGE_SETUP,
|
||||
STAGE_BRIDGE_INIT,
|
||||
STAGE_BRIDGE_RESET,
|
||||
STAGE_HOTPLUG,
|
||||
STAGE_DP_CONTROLLER,
|
||||
STAGE_BACKLIGHT_VDD,
|
||||
STAGE_BACKLIGHT_PWM,
|
||||
STAGE_BACKLIGHT_EN,
|
||||
STAGE_DONE,
|
||||
};
|
||||
|
||||
int lcd_line_length;
|
||||
int lcd_color_fg;
|
||||
int lcd_color_bg;
|
||||
|
||||
void *lcd_console_address; /* Start of console buffer */
|
||||
|
||||
short console_col;
|
||||
short console_row;
|
||||
|
||||
/* Bypass FIMD of DISP1_BLK */
|
||||
static void fimd_bypass(void)
|
||||
{
|
||||
struct exynos5_sysreg *sysreg = samsung_get_base_sysreg();
|
||||
|
||||
setbits_le32(&sysreg->disp1blk_cfg, FIMDBYPASS_DISP1);
|
||||
sysreg->disp1blk_cfg &= ~FIMDBYPASS_DISP1;
|
||||
}
|
||||
|
||||
/* Calculate the size of Framebuffer from the resolution */
|
||||
static u32 calc_fbsize(vidinfo_t *panel_info)
|
||||
{
|
||||
/* They had PAGE_SIZE here instead of 4096.
|
||||
* but that's a totally arbitrary number -- everything nowadays
|
||||
* has lots of page sizes.
|
||||
* So keep it obvious.
|
||||
*/
|
||||
return ALIGN((panel_info->vl_col * panel_info->vl_row *
|
||||
((1<<panel_info->vl_bpix) / 8)), 4096);
|
||||
}
|
||||
|
||||
/*
|
||||
* Initialize display controller.
|
||||
*
|
||||
* @param lcdbase pointer to the base address of framebuffer.
|
||||
* @pd pointer to the main panel_data structure
|
||||
*/
|
||||
void fb_init(vidinfo_t *panel_info, void *lcdbase,
|
||||
struct exynos5_fimd_panel *pd)
|
||||
{
|
||||
unsigned int val;
|
||||
u32 fbsize;
|
||||
struct exynos5_fimd *fimd = samsung_get_base_fimd();
|
||||
struct exynos5_disp_ctrl *disp_ctrl = samsung_get_base_disp_ctrl();
|
||||
|
||||
writel(pd->ivclk | pd->fixvclk, &disp_ctrl->vidcon1);
|
||||
val = ENVID_ON | ENVID_F_ON | (pd->clkval_f << CLKVAL_F_OFFSET);
|
||||
writel(val, &fimd->vidcon0);
|
||||
|
||||
val = (pd->vsync << VSYNC_PULSE_WIDTH_OFFSET) |
|
||||
(pd->lower_margin << V_FRONT_PORCH_OFFSET) |
|
||||
(pd->upper_margin << V_BACK_PORCH_OFFSET);
|
||||
writel(val, &disp_ctrl->vidtcon0);
|
||||
|
||||
val = (pd->hsync << HSYNC_PULSE_WIDTH_OFFSET) |
|
||||
(pd->right_margin << H_FRONT_PORCH_OFFSET) |
|
||||
(pd->left_margin << H_BACK_PORCH_OFFSET);
|
||||
writel(val, &disp_ctrl->vidtcon1);
|
||||
|
||||
val = ((pd->xres - 1) << HOZVAL_OFFSET) |
|
||||
((pd->yres - 1) << LINEVAL_OFFSET);
|
||||
writel(val, &disp_ctrl->vidtcon2);
|
||||
|
||||
writel((unsigned int)lcdbase, &fimd->vidw00add0b0);
|
||||
|
||||
fbsize = calc_fbsize(panel_info);
|
||||
writel((unsigned int)lcdbase + fbsize, &fimd->vidw00add1b0);
|
||||
|
||||
writel(pd->xres * 2, &fimd->vidw00add2);
|
||||
|
||||
val = ((pd->xres - 1) << OSD_RIGHTBOTX_F_OFFSET);
|
||||
val |= ((pd->yres - 1) << OSD_RIGHTBOTY_F_OFFSET);
|
||||
writel(val, &fimd->vidosd0b);
|
||||
writel(pd->xres * pd->yres, &fimd->vidosd0c);
|
||||
|
||||
setbits_le32(&fimd->shadowcon, CHANNEL0_EN);
|
||||
|
||||
val = BPPMODE_F_RGB_16BIT_565 << BPPMODE_F_OFFSET;
|
||||
val |= ENWIN_F_ENABLE | HALF_WORD_SWAP_EN;
|
||||
writel(val, &fimd->wincon0);
|
||||
|
||||
/* DPCLKCON_ENABLE */
|
||||
writel(1 << 1, &fimd->dpclkcon);
|
||||
}
|
||||
|
||||
#ifdef UNUSED_CODE
|
||||
void exynos_fimd_disable(void)
|
||||
{
|
||||
struct exynos5_fimd *fimd = samsung_get_base_fimd();
|
||||
|
||||
writel(0, &fimd->wincon0);
|
||||
clrbits_le32(&fimd->shadowcon, CHANNEL0_EN);
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Configure DP in slave mode and wait for video stream.
|
||||
*
|
||||
* param dp pointer to main s5p-dp structure
|
||||
* param video_info pointer to main video_info structure.
|
||||
* return status
|
||||
*/
|
||||
static int s5p_dp_config_video(struct s5p_dp_device *dp,
|
||||
struct video_info *video_info)
|
||||
{
|
||||
int timeout = 0;
|
||||
struct exynos5_dp *base = dp->base;
|
||||
struct mono_time start, current, end;
|
||||
s5p_dp_config_video_slave_mode(dp, video_info);
|
||||
|
||||
s5p_dp_set_video_color_format(dp, video_info->color_depth,
|
||||
video_info->color_space,
|
||||
video_info->dynamic_range,
|
||||
video_info->ycbcr_coeff);
|
||||
|
||||
if (s5p_dp_get_pll_lock_status(dp) == PLL_UNLOCKED) {
|
||||
printk(BIOS_DEBUG, "PLL is not locked yet.\n");
|
||||
return -ERR_PLL_NOT_UNLOCKED;
|
||||
}
|
||||
|
||||
timer_monotonic_get(&start);
|
||||
end = current = start;
|
||||
mono_time_add_usecs(&end, STREAM_ON_TIMEOUT * USECS_PER_MSEC);
|
||||
do {
|
||||
if (s5p_dp_is_slave_video_stream_clock_on(dp) == 0) {
|
||||
timeout++;
|
||||
break;
|
||||
}
|
||||
timer_monotonic_get(¤t);
|
||||
} while (mono_time_before(¤t, &end));
|
||||
|
||||
if (!timeout) {
|
||||
printk(BIOS_ERR, "Video Clock Not ok after %ldus.\n",
|
||||
mono_time_diff_microseconds(&start, &end));
|
||||
return -ERR_VIDEO_CLOCK_BAD;
|
||||
}
|
||||
|
||||
/* Set to use the register calculated M/N video */
|
||||
s5p_dp_set_video_cr_mn(dp, CALCULATED_M, 0, 0);
|
||||
|
||||
clrbits_le32(&base->video_ctl_10, FORMAT_SEL);
|
||||
|
||||
/* Disable video mute */
|
||||
clrbits_le32(&base->video_ctl_1, HDCP_VIDEO_MUTE);
|
||||
|
||||
/* Configure video slave mode */
|
||||
s5p_dp_enable_video_master(dp);
|
||||
|
||||
/* Enable video */
|
||||
setbits_le32(&base->video_ctl_1, VIDEO_EN);
|
||||
timeout = s5p_dp_is_video_stream_on(dp);
|
||||
|
||||
if (timeout) {
|
||||
printk(BIOS_DEBUG, "Video Stream Not on\n");
|
||||
return -ERR_VIDEO_STREAM_BAD;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Set DP to enhanced mode. We use this for EVT1
|
||||
* param dp pointer to main s5p-dp structure
|
||||
* return status
|
||||
*/
|
||||
static int s5p_dp_enable_rx_to_enhanced_mode(struct s5p_dp_device *dp)
|
||||
{
|
||||
u8 data;
|
||||
|
||||
if (s5p_dp_read_byte_from_dpcd(dp, DPCD_ADDR_LANE_COUNT_SET, &data)) {
|
||||
printk(BIOS_DEBUG, "DPCD read error\n");
|
||||
return -ERR_DPCD_READ_ERROR1;
|
||||
}
|
||||
if (s5p_dp_write_byte_to_dpcd(dp, DPCD_ADDR_LANE_COUNT_SET,
|
||||
DPCD_ENHANCED_FRAME_EN |
|
||||
(data & DPCD_LANE_COUNT_SET_MASK))) {
|
||||
printk(BIOS_DEBUG, "DPCD write error\n");
|
||||
return -ERR_DPCD_WRITE_ERROR1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Enable scrambles mode. We use this for EVT1
|
||||
* param dp pointer to main s5p-dp structure
|
||||
* return status
|
||||
*/
|
||||
static int s5p_dp_enable_scramble(struct s5p_dp_device *dp)
|
||||
{
|
||||
u8 data;
|
||||
struct exynos5_dp *base = dp->base;
|
||||
|
||||
clrbits_le32(&base->dp_training_ptn_set, SCRAMBLING_DISABLE);
|
||||
|
||||
if (s5p_dp_read_byte_from_dpcd(dp, DPCD_ADDR_TRAINING_PATTERN_SET,
|
||||
&data)) {
|
||||
printk(BIOS_DEBUG, "DPCD read error\n");
|
||||
return -ERR_DPCD_READ_ERROR2;
|
||||
}
|
||||
|
||||
if (s5p_dp_write_byte_to_dpcd(dp, DPCD_ADDR_TRAINING_PATTERN_SET,
|
||||
(u8)(data & ~DPCD_SCRAMBLING_DISABLED))) {
|
||||
printk(BIOS_DEBUG, "DPCD write error\n");
|
||||
return -ERR_DPCD_WRITE_ERROR2;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Reset DP and prepare DP for init training
|
||||
* param dp pointer to main s5p-dp structure
|
||||
*/
|
||||
static int s5p_dp_init_dp(struct s5p_dp_device *dp)
|
||||
{
|
||||
int ret, i;
|
||||
struct exynos5_dp *base = dp->base;
|
||||
|
||||
for (i = 0; i < DP_INIT_TRIES; i++) {
|
||||
s5p_dp_reset(dp);
|
||||
|
||||
/* SW defined function Normal operation */
|
||||
clrbits_le32(&base->func_en_1, SW_FUNC_EN_N);
|
||||
|
||||
ret = s5p_dp_init_analog_func(dp);
|
||||
if (!ret)
|
||||
break;
|
||||
|
||||
udelay(5000);
|
||||
printk(BIOS_DEBUG, "LCD retry init, attempt=%d ret=%d\n", i, ret);
|
||||
}
|
||||
if (i == DP_INIT_TRIES) {
|
||||
printk(BIOS_DEBUG, "LCD initialization failed, ret=%d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
s5p_dp_init_aux(dp);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Set pre-emphasis level
|
||||
* param dp pointer to main s5p-dp structure
|
||||
* param pre_emphasis pre-emphasis level
|
||||
* param lane lane number(0 - 3)
|
||||
* return status
|
||||
*/
|
||||
static int s5p_dp_set_lane_lane_pre_emphasis(struct s5p_dp_device *dp,
|
||||
int pre_emphasis, int lane)
|
||||
{
|
||||
u32 reg;
|
||||
struct exynos5_dp *base = dp->base;
|
||||
|
||||
reg = pre_emphasis << PRE_EMPHASIS_SET_SHIFT;
|
||||
switch (lane) {
|
||||
case 0:
|
||||
writel(reg, &base->ln0_link_trn_ctl);
|
||||
break;
|
||||
case 1:
|
||||
writel(reg, &base->ln1_link_trn_ctl);
|
||||
break;
|
||||
|
||||
case 2:
|
||||
writel(reg, &base->ln2_link_trn_ctl);
|
||||
break;
|
||||
|
||||
case 3:
|
||||
writel(reg, &base->ln3_link_trn_ctl);
|
||||
break;
|
||||
default:
|
||||
printk(BIOS_DEBUG, "%s: Invalid lane %d\n", __func__, lane);
|
||||
return -ERR_INVALID_LANE;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Read supported bandwidth type
|
||||
* param dp pointer to main s5p-dp structure
|
||||
* param bandwidth pointer to variable holding bandwidth type
|
||||
*/
|
||||
static void s5p_dp_get_max_rx_bandwidth(struct s5p_dp_device *dp,
|
||||
u8 *bandwidth)
|
||||
{
|
||||
u8 data;
|
||||
|
||||
/*
|
||||
* For DP rev.1.1, Maximum link rate of Main Link lanes
|
||||
* 0x06 = 1.62 Gbps, 0x0a = 2.7 Gbps
|
||||
*/
|
||||
s5p_dp_read_byte_from_dpcd(dp, DPCD_ADDR_MAX_LINK_RATE, &data);
|
||||
*bandwidth = data;
|
||||
}
|
||||
|
||||
/*
|
||||
* Reset DP and prepare DP for init training
|
||||
* param dp pointer to main s5p-dp structure
|
||||
* param lane_count pointer to variable holding no of lanes
|
||||
*/
|
||||
static void s5p_dp_get_max_rx_lane_count(struct s5p_dp_device *dp,
|
||||
u8 *lane_count)
|
||||
{
|
||||
u8 data;
|
||||
|
||||
/*
|
||||
* For DP rev.1.1, Maximum number of Main Link lanes
|
||||
* 0x01 = 1 lane, 0x02 = 2 lanes, 0x04 = 4 lanes
|
||||
*/
|
||||
s5p_dp_read_byte_from_dpcd(dp, DPCD_ADDR_MAX_LANE_COUNT, &data);
|
||||
*lane_count = data & DPCD_MAX_LANE_COUNT_MASK;
|
||||
}
|
||||
|
||||
/*
|
||||
* DP H/w Link Training. Set DPCD link rate and bandwidth.
|
||||
* param dp pointer to main s5p-dp structure
|
||||
* param max_lane No of lanes
|
||||
* param max_rate bandwidth
|
||||
* return status
|
||||
*/
|
||||
static int s5p_dp_hw_link_training(struct s5p_dp_device *dp,
|
||||
unsigned int max_lane,
|
||||
unsigned int max_rate)
|
||||
{
|
||||
int pll_is_locked = 0;
|
||||
u32 data;
|
||||
u32 start;
|
||||
int lane;
|
||||
struct exynos5_dp *base = dp->base;
|
||||
|
||||
/* Stop Video */
|
||||
clrbits_le32(&base->video_ctl_1, VIDEO_EN);
|
||||
|
||||
start = get_timer(0);
|
||||
while ((pll_is_locked = s5p_dp_get_pll_lock_status(dp)) == PLL_UNLOCKED) {
|
||||
if (get_timer(start) > PLL_LOCK_TIMEOUT) {
|
||||
/* Ignore this error, and try to continue */
|
||||
printk(BIOS_ERR, "PLL is not locked yet.\n");
|
||||
break;
|
||||
}
|
||||
}
|
||||
printk(BIOS_SPEW, "PLL is %slocked\n",
|
||||
pll_is_locked == PLL_LOCKED ? "": "not ");
|
||||
/* Reset Macro */
|
||||
setbits_le32(&base->dp_phy_test, MACRO_RST);
|
||||
|
||||
/* 10 us is the minimum reset time. */
|
||||
udelay(10);
|
||||
|
||||
clrbits_le32(&base->dp_phy_test, MACRO_RST);
|
||||
|
||||
/* Set TX pre-emphasis to minimum */
|
||||
for (lane = 0; lane < max_lane; lane++)
|
||||
if (s5p_dp_set_lane_lane_pre_emphasis(dp,
|
||||
PRE_EMPHASIS_LEVEL_0, lane)) {
|
||||
printk(BIOS_DEBUG, "Unable to set pre emphasis level\n");
|
||||
return -ERR_PRE_EMPHASIS_LEVELS;
|
||||
}
|
||||
|
||||
/* All DP analog module power up */
|
||||
writel(0x00, &base->dp_phy_pd);
|
||||
|
||||
/* Initialize by reading RX's DPCD */
|
||||
s5p_dp_get_max_rx_bandwidth(dp, &dp->link_train.link_rate);
|
||||
s5p_dp_get_max_rx_lane_count(dp, &dp->link_train.lane_count);
|
||||
|
||||
printk(BIOS_SPEW, "%s: rate 0x%x, lane_count %d\n", __func__,
|
||||
dp->link_train.link_rate, dp->link_train.lane_count);
|
||||
|
||||
if ((dp->link_train.link_rate != LINK_RATE_1_62GBPS) &&
|
||||
(dp->link_train.link_rate != LINK_RATE_2_70GBPS)) {
|
||||
printk(BIOS_DEBUG, "Rx Max Link Rate is abnormal :%x !\n",
|
||||
dp->link_train.link_rate);
|
||||
/* Not Retrying */
|
||||
return -ERR_LINK_RATE_ABNORMAL;
|
||||
}
|
||||
|
||||
if (dp->link_train.lane_count == 0) {
|
||||
printk(BIOS_DEBUG, "Rx Max Lane count is abnormal :%x !\n",
|
||||
dp->link_train.lane_count);
|
||||
/* Not retrying */
|
||||
return -ERR_MAX_LANE_COUNT_ABNORMAL;
|
||||
}
|
||||
|
||||
/* Setup TX lane count & rate */
|
||||
if (dp->link_train.lane_count > max_lane)
|
||||
dp->link_train.lane_count = max_lane;
|
||||
if (dp->link_train.link_rate > max_rate)
|
||||
dp->link_train.link_rate = max_rate;
|
||||
|
||||
/* Set link rate and count as you want to establish*/
|
||||
writel(dp->link_train.lane_count, &base->lane_count_set);
|
||||
writel(dp->link_train.link_rate, &base->link_bw_set);
|
||||
|
||||
/* Set sink to D0 (Sink Not Ready) mode. */
|
||||
s5p_dp_write_byte_to_dpcd(dp, DPCD_ADDR_SINK_POWER_STATE,
|
||||
DPCD_SET_POWER_STATE_D0);
|
||||
|
||||
/* Start HW link training */
|
||||
writel(HW_TRAINING_EN, &base->dp_hw_link_training);
|
||||
|
||||
/* Wait until HW link training done */
|
||||
s5p_dp_wait_hw_link_training_done(dp);
|
||||
|
||||
/* Get hardware link training status */
|
||||
data = readl(&base->dp_hw_link_training);
|
||||
printk(BIOS_SPEW, "hardware link training status: 0x%08x\n", data);
|
||||
if (data != 0) {
|
||||
printk(BIOS_ERR, " H/W link training failure: 0x%x\n", data);
|
||||
return -ERR_LINK_TRAINING_FAILURE;
|
||||
}
|
||||
|
||||
/* Get Link Bandwidth */
|
||||
data = readl(&base->link_bw_set);
|
||||
|
||||
dp->link_train.link_rate = data;
|
||||
|
||||
data = readl(&base->lane_count_set);
|
||||
dp->link_train.lane_count = data;
|
||||
printk(BIOS_SPEW, "Done training: Link bandwidth: 0x%x, lane_count: %d\n",
|
||||
dp->link_train.link_rate, data);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Initialize DP display
|
||||
*/
|
||||
int dp_controller_init(struct s5p_dp_device *dp_device)
|
||||
{
|
||||
int ret;
|
||||
struct s5p_dp_device *dp = dp_device;
|
||||
struct exynos5_dp *base;
|
||||
|
||||
clock_init_dp_clock();
|
||||
|
||||
power_enable_dp_phy();
|
||||
ret = s5p_dp_init_dp(dp);
|
||||
if (ret) {
|
||||
printk(BIOS_ERR, "%s: Could not initialize dp\n", __func__);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = s5p_dp_hw_link_training(dp, dp->video_info->lane_count,
|
||||
dp->video_info->link_rate);
|
||||
if (ret) {
|
||||
printk(BIOS_ERR, "unable to do link train\n");
|
||||
return ret;
|
||||
}
|
||||
/* Minimum delay after H/w Link training */
|
||||
udelay(1000);
|
||||
|
||||
ret = s5p_dp_enable_scramble(dp);
|
||||
if (ret) {
|
||||
printk(BIOS_ERR, "unable to set scramble mode\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = s5p_dp_enable_rx_to_enhanced_mode(dp);
|
||||
if (ret) {
|
||||
printk(BIOS_ERR, "unable to set enhanced mode\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
base = dp->base;
|
||||
/* Enable enhanced mode */
|
||||
setbits_le32(&base->sys_ctl_4, ENHANCED);
|
||||
|
||||
writel(dp->link_train.lane_count, &base->lane_count_set);
|
||||
writel(dp->link_train.link_rate, &base->link_bw_set);
|
||||
|
||||
s5p_dp_init_video(dp);
|
||||
ret = s5p_dp_config_video(dp, dp->video_info);
|
||||
if (ret) {
|
||||
printk(BIOS_ERR, "unable to config video\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Init the LCD controller
|
||||
*
|
||||
* @param lcdbase Base address of LCD frame buffer
|
||||
* @return 0 if ok, -ve error code on error
|
||||
*/
|
||||
int lcd_ctrl_init(vidinfo_t *panel_info,
|
||||
struct exynos5_fimd_panel *panel_data, void *lcdbase)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
fimd_bypass();
|
||||
fb_init(panel_info, lcdbase, panel_data);
|
||||
return ret;
|
||||
}
|
|
@ -0,0 +1,138 @@
|
|||
/*
|
||||
* This file is part of the coreboot project.
|
||||
*
|
||||
* Copyright (C) 2012 Samsung Electronics
|
||||
*
|
||||
* 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; version 2 of 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
/* Register map for Exynos5 FIMD */
|
||||
|
||||
#ifndef CPU_SAMSUNG_EXYNOS5420_FIMD_H
|
||||
#define CPU_SAMSUNG_EXYNOS5420_FIMD_H
|
||||
|
||||
/* FIMD register map */
|
||||
struct exynos5_fimd {
|
||||
/* This is an incomplete list. Add registers as and when required */
|
||||
unsigned int vidcon0;
|
||||
unsigned char res1[0x1c];
|
||||
unsigned int wincon0;
|
||||
unsigned int wincon1;
|
||||
unsigned int wincon2;
|
||||
unsigned int wincon3;
|
||||
unsigned int wincon4;
|
||||
unsigned int shadowcon;
|
||||
unsigned char res2[0x8];
|
||||
unsigned int vidosd0a;
|
||||
unsigned int vidosd0b;
|
||||
unsigned int vidosd0c;
|
||||
unsigned char res3[0x54];
|
||||
unsigned int vidw00add0b0;
|
||||
unsigned char res4[0x2c];
|
||||
unsigned int vidw00add1b0;
|
||||
unsigned char res5[0x2c];
|
||||
unsigned int vidw00add2;
|
||||
unsigned char res6[0x3c];
|
||||
unsigned int w1keycon0;
|
||||
unsigned int w1keycon1;
|
||||
unsigned int w2keycon0;
|
||||
unsigned int w2keycon1;
|
||||
unsigned int w3keycon0;
|
||||
unsigned int w3keycon1;
|
||||
unsigned int w4keycon0;
|
||||
unsigned int w4keycon1;
|
||||
unsigned char res7[0x20];
|
||||
unsigned int win0map;
|
||||
unsigned char res8[0xdc];
|
||||
unsigned int blendcon;
|
||||
unsigned char res9[0x18];
|
||||
unsigned int dpclkcon;
|
||||
};
|
||||
|
||||
#define W0_SHADOW_PROTECT (0x1 << 10)
|
||||
#define COMPKEY_F 0xffffff
|
||||
#define ENVID_F_ON (0x1 << 0)
|
||||
#define ENVID_ON (0x1 << 1)
|
||||
#define CLKVAL_F 0xb
|
||||
#define CLKVAL_F_OFFSET 6
|
||||
|
||||
/*
|
||||
* Structure containing display panel specific data for FIMD
|
||||
*/
|
||||
struct exynos5_fimd_panel {
|
||||
unsigned int is_dp:1; /* Display Panel interface is eDP */
|
||||
unsigned int is_mipi:1; /* Display Panel interface is MIPI */
|
||||
unsigned int fixvclk:2; /* VCLK hold scheme at data underflow */
|
||||
|
||||
/*
|
||||
* Polarity of the VCLK active edge
|
||||
* 0-falling
|
||||
* 1-rising
|
||||
*/
|
||||
unsigned int ivclk:1;
|
||||
unsigned int clkval_f; /* Divider to create pixel clock */
|
||||
|
||||
unsigned int upper_margin; /* Vertical Backporch */
|
||||
unsigned int lower_margin; /* Vertical frontporch */
|
||||
unsigned int vsync; /* Vertical Sync Pulse Width */
|
||||
unsigned int left_margin; /* Horizantal Backporch */
|
||||
unsigned int right_margin; /* Horizontal Frontporch */
|
||||
unsigned int hsync; /* Horizontal Sync Pulse Width */
|
||||
unsigned int xres; /* X Resolution */
|
||||
unsigned int yres; /* Y Resopultion */
|
||||
};
|
||||
|
||||
/* LCDIF Register Map */
|
||||
struct exynos5_disp_ctrl {
|
||||
unsigned int vidout_con;
|
||||
unsigned int vidcon1;
|
||||
unsigned char res1[0x8];
|
||||
unsigned int vidtcon0;
|
||||
unsigned int vidtcon1;
|
||||
unsigned int vidtcon2;
|
||||
unsigned int vidtcon3;
|
||||
unsigned char res2[0x184];
|
||||
unsigned int trigcon;
|
||||
};
|
||||
|
||||
#define VCLK_RISING_EDGE (1 << 7)
|
||||
#define VCLK_RUNNING (1 << 9)
|
||||
|
||||
#define CHANNEL0_EN (1 << 0)
|
||||
|
||||
#define VSYNC_PULSE_WIDTH_VAL 0x3
|
||||
#define VSYNC_PULSE_WIDTH_OFFSET 0
|
||||
#define V_FRONT_PORCH_VAL 0x3
|
||||
#define V_FRONT_PORCH_OFFSET 8
|
||||
#define V_BACK_PORCH_VAL 0x3
|
||||
#define V_BACK_PORCH_OFFSET 16
|
||||
|
||||
#define HSYNC_PULSE_WIDTH_VAL 0x3
|
||||
#define HSYNC_PULSE_WIDTH_OFFSET 0
|
||||
#define H_FRONT_PORCH_VAL 0x3
|
||||
#define H_FRONT_PORCH_OFFSET 8
|
||||
#define H_BACK_PORCH_VAL 0x3
|
||||
#define H_BACK_PORCH_OFFSET 16
|
||||
|
||||
#define HOZVAL_OFFSET 0
|
||||
#define LINEVAL_OFFSET 11
|
||||
|
||||
#define BPPMODE_F_RGB_16BIT_565 0x5
|
||||
#define BPPMODE_F_OFFSET 2
|
||||
#define ENWIN_F_ENABLE (1 << 0)
|
||||
#define HALF_WORD_SWAP_EN (1 << 16)
|
||||
|
||||
#define OSD_RIGHTBOTX_F_OFFSET 11
|
||||
#define OSD_RIGHTBOTY_F_OFFSET 0
|
||||
#endif
|
|
@ -0,0 +1,279 @@
|
|||
/*
|
||||
* This file is part of the coreboot project.
|
||||
*
|
||||
* Copyright (C) 2009 Samsung Electronics
|
||||
*
|
||||
* 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; version 2 of 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include <console/console.h>
|
||||
#include <string.h>
|
||||
#include <delay.h>
|
||||
#include <assert.h>
|
||||
#include "gpio.h"
|
||||
#include "cpu.h"
|
||||
|
||||
#define CON_MASK(x) (0xf << ((x) << 2))
|
||||
#define CON_SFR(x, v) ((v) << ((x) << 2))
|
||||
|
||||
#define DAT_MASK(x) (0x1 << (x))
|
||||
#define DAT_SET(x) (0x1 << (x))
|
||||
|
||||
#define PULL_MASK(x) (0x3 << ((x) << 1))
|
||||
#define PULL_MODE(x, v) ((v) << ((x) << 1))
|
||||
|
||||
#define DRV_MASK(x) (0x3 << ((x) << 1))
|
||||
#define DRV_SET(x, m) ((m) << ((x) << 1))
|
||||
#define RATE_MASK(x) (0x1 << (x + 16))
|
||||
#define RATE_SET(x) (0x1 << (x + 16))
|
||||
|
||||
struct gpio_info {
|
||||
unsigned int reg_addr; /* Address of register for this part */
|
||||
unsigned int max_gpio; /* Maximum GPIO in this part */
|
||||
};
|
||||
|
||||
static const struct gpio_info gpio_data[EXYNOS_GPIO_NUM_PARTS] = {
|
||||
{ EXYNOS5_GPIO_PART1_BASE, GPIO_MAX_PORT_PART_1 },
|
||||
{ EXYNOS5_GPIO_PART2_BASE, GPIO_MAX_PORT_PART_2 },
|
||||
{ EXYNOS5_GPIO_PART3_BASE, GPIO_MAX_PORT_PART_3 },
|
||||
{ EXYNOS5_GPIO_PART4_BASE, GPIO_MAX_PORT_PART_4 },
|
||||
{ EXYNOS5_GPIO_PART5_BASE, GPIO_MAX_PORT_PART_5 },
|
||||
{ EXYNOS5_GPIO_PART6_BASE, GPIO_MAX_PORT },
|
||||
};
|
||||
|
||||
/* This macro gets gpio pin offset from 0..7 */
|
||||
#define GPIO_BIT(x) ((x) & 0x7)
|
||||
|
||||
static struct gpio_bank *gpio_get_bank(unsigned int gpio)
|
||||
{
|
||||
const struct gpio_info *data;
|
||||
unsigned int upto;
|
||||
int i;
|
||||
|
||||
for (i = upto = 0, data = gpio_data; i < EXYNOS_GPIO_NUM_PARTS;
|
||||
i++, upto = data->max_gpio, data++) {
|
||||
if (gpio < data->max_gpio) {
|
||||
struct gpio_bank *bank;
|
||||
|
||||
bank = (struct gpio_bank *)data->reg_addr;
|
||||
bank += (gpio - upto) / GPIO_PER_BANK;
|
||||
return bank;
|
||||
}
|
||||
}
|
||||
|
||||
ASSERT(gpio < GPIO_MAX_PORT); /* ...which it will not be */
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Common GPIO API - only available on Exynos5 */
|
||||
void gpio_cfg_pin(int gpio, int cfg)
|
||||
{
|
||||
unsigned int value;
|
||||
struct gpio_bank *bank = gpio_get_bank(gpio);
|
||||
|
||||
value = readl(&bank->con);
|
||||
value &= ~CON_MASK(GPIO_BIT(gpio));
|
||||
value |= CON_SFR(GPIO_BIT(gpio), cfg);
|
||||
writel(value, &bank->con);
|
||||
}
|
||||
|
||||
static int gpio_get_cfg(int gpio)
|
||||
{
|
||||
struct gpio_bank *bank = gpio_get_bank(gpio);
|
||||
int shift = GPIO_BIT(gpio) << 2;
|
||||
|
||||
return (readl(&bank->con) & CON_MASK(GPIO_BIT(gpio))) >> shift;
|
||||
}
|
||||
|
||||
void gpio_set_pull(int gpio, int mode)
|
||||
{
|
||||
unsigned int value;
|
||||
struct gpio_bank *bank = gpio_get_bank(gpio);
|
||||
|
||||
value = readl(&bank->pull);
|
||||
value &= ~PULL_MASK(GPIO_BIT(gpio));
|
||||
|
||||
switch (mode) {
|
||||
case GPIO_PULL_DOWN:
|
||||
case GPIO_PULL_UP:
|
||||
value |= PULL_MODE(GPIO_BIT(gpio), mode);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
writel(value, &bank->pull);
|
||||
}
|
||||
|
||||
void gpio_set_drv(int gpio, int mode)
|
||||
{
|
||||
unsigned int value;
|
||||
struct gpio_bank *bank = gpio_get_bank(gpio);
|
||||
|
||||
value = readl(&bank->drv);
|
||||
value &= ~DRV_MASK(GPIO_BIT(gpio));
|
||||
|
||||
switch (mode) {
|
||||
case GPIO_DRV_1X:
|
||||
case GPIO_DRV_2X:
|
||||
case GPIO_DRV_3X:
|
||||
case GPIO_DRV_4X:
|
||||
value |= DRV_SET(GPIO_BIT(gpio), mode);
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
|
||||
writel(value, &bank->drv);
|
||||
}
|
||||
|
||||
void gpio_set_rate(int gpio, int mode)
|
||||
{
|
||||
unsigned int value;
|
||||
struct gpio_bank *bank = gpio_get_bank(gpio);
|
||||
|
||||
value = readl(&bank->drv);
|
||||
value &= ~RATE_MASK(GPIO_BIT(gpio));
|
||||
|
||||
switch (mode) {
|
||||
case GPIO_DRV_FAST:
|
||||
case GPIO_DRV_SLOW:
|
||||
value |= RATE_SET(GPIO_BIT(gpio));
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
|
||||
writel(value, &bank->drv);
|
||||
}
|
||||
|
||||
int gpio_direction_input(unsigned gpio)
|
||||
{
|
||||
gpio_cfg_pin(gpio, GPIO_INPUT);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int gpio_direction_output(unsigned gpio, int value)
|
||||
{
|
||||
unsigned int val;
|
||||
struct gpio_bank *bank = gpio_get_bank(gpio);
|
||||
|
||||
gpio_cfg_pin(gpio, GPIO_OUTPUT);
|
||||
|
||||
val = readl(&bank->dat);
|
||||
val &= ~DAT_MASK(GPIO_BIT(gpio));
|
||||
if (value)
|
||||
val |= DAT_SET(GPIO_BIT(gpio));
|
||||
writel(val, &bank->dat);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int gpio_get_value(unsigned gpio)
|
||||
{
|
||||
unsigned int value;
|
||||
struct gpio_bank *bank = gpio_get_bank(gpio);
|
||||
|
||||
value = readl(&bank->dat);
|
||||
return !!(value & DAT_MASK(GPIO_BIT(gpio)));
|
||||
}
|
||||
|
||||
int gpio_set_value(unsigned gpio, int value)
|
||||
{
|
||||
unsigned int val;
|
||||
struct gpio_bank *bank = gpio_get_bank(gpio);
|
||||
|
||||
val = readl(&bank->dat);
|
||||
val &= ~DAT_MASK(GPIO_BIT(gpio));
|
||||
if (value)
|
||||
val |= DAT_SET(GPIO_BIT(gpio));
|
||||
writel(val, &bank->dat);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Add a delay here to give the lines time to settle
|
||||
* TODO(sjg): 1us does not always work, 2 is stable, so use 5 to be safe
|
||||
* Come back to this and sort out what the datasheet says
|
||||
*/
|
||||
#define GPIO_DELAY_US 5
|
||||
|
||||
#ifndef __BOOT_BLOCK__
|
||||
/*
|
||||
* FIXME(dhendrix): These functions use udelay, which has dependencies on
|
||||
* pwm code and timer code. These aren't necessary for the bootblock and
|
||||
* bloat the image significantly.
|
||||
*/
|
||||
int gpio_read_mvl3(unsigned gpio)
|
||||
{
|
||||
int high, low;
|
||||
enum mvl3 value;
|
||||
|
||||
if (gpio >= GPIO_MAX_PORT)
|
||||
return -1;
|
||||
|
||||
gpio_direction_input(gpio);
|
||||
gpio_set_pull(gpio, GPIO_PULL_UP);
|
||||
udelay(GPIO_DELAY_US);
|
||||
high = gpio_get_value(gpio);
|
||||
gpio_set_pull(gpio, GPIO_PULL_DOWN);
|
||||
udelay(GPIO_DELAY_US);
|
||||
low = gpio_get_value(gpio);
|
||||
|
||||
if (high && low) /* external pullup */
|
||||
value = LOGIC_1;
|
||||
else if (!high && !low) /* external pulldown */
|
||||
value = LOGIC_0;
|
||||
else /* floating */
|
||||
value = LOGIC_Z;
|
||||
|
||||
/*
|
||||
* Check if line is externally pulled high and
|
||||
* configure the internal pullup to match. For
|
||||
* floating and pulldowns, the GPIO is already
|
||||
* configured with an internal pulldown from the
|
||||
* above test.
|
||||
*/
|
||||
if (value == LOGIC_1)
|
||||
gpio_set_pull(gpio, GPIO_PULL_UP);
|
||||
|
||||
return value;
|
||||
}
|
||||
#endif /* __BOOT_BLOCK__ */
|
||||
|
||||
/*
|
||||
* Display Exynos GPIO information
|
||||
*/
|
||||
void gpio_info(void)
|
||||
{
|
||||
unsigned gpio;
|
||||
|
||||
for (gpio = 0; gpio < GPIO_MAX_PORT; gpio++) {
|
||||
int cfg = gpio_get_cfg(gpio);
|
||||
|
||||
printk(BIOS_INFO, "GPIO_%-3d: ", gpio);
|
||||
if (cfg == GPIO_INPUT)
|
||||
printk(BIOS_INFO, "input");
|
||||
else if (cfg == GPIO_OUTPUT)
|
||||
printk(BIOS_INFO, "output");
|
||||
else
|
||||
printk(BIOS_INFO, "func %d", cfg);
|
||||
|
||||
if (cfg == GPIO_INPUT || cfg == GPIO_OUTPUT)
|
||||
printk(BIOS_INFO, ", value = %d", gpio_get_value(gpio));
|
||||
printk(BIOS_INFO, "\n");
|
||||
}
|
||||
}
|
|
@ -0,0 +1,578 @@
|
|||
/*
|
||||
* This file is part of the coreboot project.
|
||||
*
|
||||
* Copyright (C) 2010 Samsung Electronics
|
||||
*
|
||||
* 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; version 2 of 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#ifndef CPU_SAMSUNG_EXYNOS5420_GPIO_H
|
||||
#define CPU_SAMSUNG_EXYNOS5420_GPIO_H
|
||||
|
||||
struct gpio_bank {
|
||||
unsigned int con;
|
||||
unsigned int dat;
|
||||
unsigned int pull;
|
||||
unsigned int drv;
|
||||
unsigned int pdn_con;
|
||||
unsigned int pdn_pull;
|
||||
unsigned char res1[8];
|
||||
};
|
||||
|
||||
/* GPIO pins per bank */
|
||||
#define GPIO_PER_BANK 8
|
||||
|
||||
/* Pin configurations */
|
||||
#define GPIO_INPUT 0x0
|
||||
#define GPIO_OUTPUT 0x1
|
||||
#define GPIO_IRQ 0xf
|
||||
#define GPIO_FUNC(x) (x)
|
||||
|
||||
/* Pull mode */
|
||||
#define GPIO_PULL_NONE 0x0
|
||||
#define GPIO_PULL_DOWN 0x1
|
||||
#define GPIO_PULL_UP 0x3
|
||||
|
||||
/* Drive Strength level */
|
||||
#define GPIO_DRV_1X 0x0
|
||||
#define GPIO_DRV_3X 0x1
|
||||
#define GPIO_DRV_2X 0x2
|
||||
#define GPIO_DRV_4X 0x3
|
||||
#define GPIO_DRV_FAST 0x0
|
||||
#define GPIO_DRV_SLOW 0x1
|
||||
|
||||
#define EXYNOS5_GPIO_BASE0 0x11400000
|
||||
#define EXYNOS5_GPIO_BASE1 0x13400000
|
||||
#define EXYNOS5_GPIO_BASE2 0x10d10000
|
||||
#define EXYNOS5_GPIO_BASE3 0x03860000
|
||||
|
||||
enum exynos5_gpio_port {
|
||||
/*
|
||||
* Ordered by base address + offset.
|
||||
* ETC registers are special, thus not included.
|
||||
*/
|
||||
|
||||
/* base == EXYNOS_GPIO_BASE0 */
|
||||
EXYNOS5_GPA0 = EXYNOS5_GPIO_BASE0 + 0x0000,
|
||||
EXYNOS5_GPA1 = EXYNOS5_GPIO_BASE0 + 0x0020,
|
||||
EXYNOS5_GPA2 = EXYNOS5_GPIO_BASE0 + 0x0040,
|
||||
|
||||
EXYNOS5_GPB0 = EXYNOS5_GPIO_BASE0 + 0x0060,
|
||||
EXYNOS5_GPB1 = EXYNOS5_GPIO_BASE0 + 0x0080,
|
||||
EXYNOS5_GPB2 = EXYNOS5_GPIO_BASE0 + 0x00a0,
|
||||
EXYNOS5_GPB3 = EXYNOS5_GPIO_BASE0 + 0x00c0,
|
||||
|
||||
EXYNOS5_GPC0 = EXYNOS5_GPIO_BASE0 + 0x00e0,
|
||||
EXYNOS5_GPC1 = EXYNOS5_GPIO_BASE0 + 0x0100,
|
||||
EXYNOS5_GPC2 = EXYNOS5_GPIO_BASE0 + 0x0120,
|
||||
EXYNOS5_GPC3 = EXYNOS5_GPIO_BASE0 + 0x0140,
|
||||
|
||||
EXYNOS5_GPD0 = EXYNOS5_GPIO_BASE0 + 0x0160,
|
||||
EXYNOS5_GPD1 = EXYNOS5_GPIO_BASE0 + 0x0180,
|
||||
|
||||
EXYNOS5_GPY0 = EXYNOS5_GPIO_BASE0 + 0x01a0,
|
||||
EXYNOS5_GPY1 = EXYNOS5_GPIO_BASE0 + 0x01c0,
|
||||
EXYNOS5_GPY2 = EXYNOS5_GPIO_BASE0 + 0x01e0,
|
||||
EXYNOS5_GPY3 = EXYNOS5_GPIO_BASE0 + 0x0200,
|
||||
EXYNOS5_GPY4 = EXYNOS5_GPIO_BASE0 + 0x0220,
|
||||
EXYNOS5_GPY5 = EXYNOS5_GPIO_BASE0 + 0x0240,
|
||||
EXYNOS5_GPY6 = EXYNOS5_GPIO_BASE0 + 0x0260,
|
||||
|
||||
EXYNOS5_GPX0 = EXYNOS5_GPIO_BASE0 + 0x0c00,
|
||||
EXYNOS5_GPX1 = EXYNOS5_GPIO_BASE0 + 0x0c20,
|
||||
EXYNOS5_GPX2 = EXYNOS5_GPIO_BASE0 + 0x0c40,
|
||||
EXYNOS5_GPX3 = EXYNOS5_GPIO_BASE0 + 0x0c60,
|
||||
|
||||
/* base == EXYNOS_GPIO_BASE1 */
|
||||
EXYNOS5_GPE0 = EXYNOS5_GPIO_BASE1 + 0x0000,
|
||||
EXYNOS5_GPE1 = EXYNOS5_GPIO_BASE1 + 0x0020,
|
||||
|
||||
EXYNOS5_GPF0 = EXYNOS5_GPIO_BASE1 + 0x0040,
|
||||
EXYNOS5_GPF1 = EXYNOS5_GPIO_BASE1 + 0x0060,
|
||||
|
||||
EXYNOS5_GPG0 = EXYNOS5_GPIO_BASE1 + 0x0080,
|
||||
EXYNOS5_GPG1 = EXYNOS5_GPIO_BASE1 + 0x00a0,
|
||||
EXYNOS5_GPG2 = EXYNOS5_GPIO_BASE1 + 0x00c0,
|
||||
|
||||
EXYNOS5_GPH0 = EXYNOS5_GPIO_BASE1 + 0x00e0,
|
||||
EXYNOS5_GPH1 = EXYNOS5_GPIO_BASE1 + 0x0100,
|
||||
|
||||
/* base == EXYNOS_GPIO_BASE2 */
|
||||
EXYNOS5_GPV0 = EXYNOS5_GPIO_BASE2 + 0x0000,
|
||||
EXYNOS5_GPV1 = EXYNOS5_GPIO_BASE2 + 0x0020,
|
||||
EXYNOS5_GPV2 = EXYNOS5_GPIO_BASE2 + 0x0060,
|
||||
EXYNOS5_GPV3 = EXYNOS5_GPIO_BASE2 + 0x0080,
|
||||
EXYNOS5_GPV4 = EXYNOS5_GPIO_BASE2 + 0x00c0,
|
||||
|
||||
/* base == EXYNOS_GPIO_BASE3 */
|
||||
EXYNOS5_GPZ = EXYNOS5_GPIO_BASE3 + 0x0000,
|
||||
};
|
||||
|
||||
enum {
|
||||
/* GPIO banks are split into this many parts */
|
||||
EXYNOS_GPIO_NUM_PARTS = 6
|
||||
};
|
||||
|
||||
/* A list of valid GPIO numbers for the asm-generic/gpio.h interface */
|
||||
enum exynos5_gpio_pin {
|
||||
/* GPIO_PART1_STARTS */
|
||||
GPIO_A00,
|
||||
GPIO_A01,
|
||||
GPIO_A02,
|
||||
GPIO_A03,
|
||||
GPIO_A04,
|
||||
GPIO_A05,
|
||||
GPIO_A06,
|
||||
GPIO_A07,
|
||||
GPIO_A10,
|
||||
GPIO_A11,
|
||||
GPIO_A12,
|
||||
GPIO_A13,
|
||||
GPIO_A14,
|
||||
GPIO_A15,
|
||||
GPIO_A16,
|
||||
GPIO_A17,
|
||||
GPIO_A20,
|
||||
GPIO_A21,
|
||||
GPIO_A22,
|
||||
GPIO_A23,
|
||||
GPIO_A24,
|
||||
GPIO_A25,
|
||||
GPIO_A26,
|
||||
GPIO_A27,
|
||||
GPIO_B00, /* 0x18 */
|
||||
GPIO_B01,
|
||||
GPIO_B02,
|
||||
GPIO_B03,
|
||||
GPIO_B04,
|
||||
GPIO_B05,
|
||||
GPIO_B06,
|
||||
GPIO_B07,
|
||||
GPIO_B10,
|
||||
GPIO_B11,
|
||||
GPIO_B12,
|
||||
GPIO_B13,
|
||||
GPIO_B14,
|
||||
GPIO_B15,
|
||||
GPIO_B16,
|
||||
GPIO_B17,
|
||||
GPIO_B20,
|
||||
GPIO_B21,
|
||||
GPIO_B22,
|
||||
GPIO_B23,
|
||||
GPIO_B24,
|
||||
GPIO_B25,
|
||||
GPIO_B26,
|
||||
GPIO_B27,
|
||||
GPIO_B30,
|
||||
GPIO_B31,
|
||||
GPIO_B32,
|
||||
GPIO_B33,
|
||||
GPIO_B34,
|
||||
GPIO_B35,
|
||||
GPIO_B36,
|
||||
GPIO_B37,
|
||||
GPIO_C00, /* 0x38 */
|
||||
GPIO_C01,
|
||||
GPIO_C02,
|
||||
GPIO_C03,
|
||||
GPIO_C04,
|
||||
GPIO_C05,
|
||||
GPIO_C06,
|
||||
GPIO_C07,
|
||||
GPIO_C10,
|
||||
GPIO_C11,
|
||||
GPIO_C12,
|
||||
GPIO_C13,
|
||||
GPIO_C14,
|
||||
GPIO_C15,
|
||||
GPIO_C16,
|
||||
GPIO_C17,
|
||||
GPIO_C20,
|
||||
GPIO_C21,
|
||||
GPIO_C22,
|
||||
GPIO_C23,
|
||||
GPIO_C24,
|
||||
GPIO_C25,
|
||||
GPIO_C26,
|
||||
GPIO_C27,
|
||||
GPIO_C30,
|
||||
GPIO_C31,
|
||||
GPIO_C32,
|
||||
GPIO_C33,
|
||||
GPIO_C34,
|
||||
GPIO_C35,
|
||||
GPIO_C36,
|
||||
GPIO_C37,
|
||||
GPIO_D00, /* 0x58 */
|
||||
GPIO_D01,
|
||||
GPIO_D02,
|
||||
GPIO_D03,
|
||||
GPIO_D04,
|
||||
GPIO_D05,
|
||||
GPIO_D06,
|
||||
GPIO_D07,
|
||||
GPIO_D10,
|
||||
GPIO_D11,
|
||||
GPIO_D12,
|
||||
GPIO_D13,
|
||||
GPIO_D14,
|
||||
GPIO_D15,
|
||||
GPIO_D16,
|
||||
GPIO_D17,
|
||||
GPIO_Y00, /* 0x68 */
|
||||
GPIO_Y01,
|
||||
GPIO_Y02,
|
||||
GPIO_Y03,
|
||||
GPIO_Y04,
|
||||
GPIO_Y05,
|
||||
GPIO_Y06,
|
||||
GPIO_Y07,
|
||||
GPIO_Y10,
|
||||
GPIO_Y11,
|
||||
GPIO_Y12,
|
||||
GPIO_Y13,
|
||||
GPIO_Y14,
|
||||
GPIO_Y15,
|
||||
GPIO_Y16,
|
||||
GPIO_Y17,
|
||||
GPIO_Y20,
|
||||
GPIO_Y21,
|
||||
GPIO_Y22,
|
||||
GPIO_Y23,
|
||||
GPIO_Y24,
|
||||
GPIO_Y25,
|
||||
GPIO_Y26,
|
||||
GPIO_Y27,
|
||||
GPIO_Y30,
|
||||
GPIO_Y31,
|
||||
GPIO_Y32,
|
||||
GPIO_Y33,
|
||||
GPIO_Y34,
|
||||
GPIO_Y35,
|
||||
GPIO_Y36,
|
||||
GPIO_Y37,
|
||||
GPIO_Y40,
|
||||
GPIO_Y41,
|
||||
GPIO_Y42,
|
||||
GPIO_Y43,
|
||||
GPIO_Y44,
|
||||
GPIO_Y45,
|
||||
GPIO_Y46,
|
||||
GPIO_Y47,
|
||||
GPIO_Y50,
|
||||
GPIO_Y51,
|
||||
GPIO_Y52,
|
||||
GPIO_Y53,
|
||||
GPIO_Y54,
|
||||
GPIO_Y55,
|
||||
GPIO_Y56,
|
||||
GPIO_Y57,
|
||||
GPIO_Y60,
|
||||
GPIO_Y61,
|
||||
GPIO_Y62,
|
||||
GPIO_Y63,
|
||||
GPIO_Y64,
|
||||
GPIO_Y65,
|
||||
GPIO_Y66,
|
||||
GPIO_Y67,
|
||||
|
||||
/* GPIO_PART2_STARTS */
|
||||
GPIO_MAX_PORT_PART_1,
|
||||
GPIO_X00 = GPIO_MAX_PORT_PART_1, /* 0xa0 */
|
||||
GPIO_X01,
|
||||
GPIO_X02,
|
||||
GPIO_X03,
|
||||
GPIO_X04,
|
||||
GPIO_X05,
|
||||
GPIO_X06,
|
||||
GPIO_X07,
|
||||
GPIO_X10,
|
||||
GPIO_X11,
|
||||
GPIO_X12,
|
||||
GPIO_X13,
|
||||
GPIO_X14,
|
||||
GPIO_X15,
|
||||
GPIO_X16,
|
||||
GPIO_X17,
|
||||
GPIO_X20,
|
||||
GPIO_X21,
|
||||
GPIO_X22,
|
||||
GPIO_X23,
|
||||
GPIO_X24,
|
||||
GPIO_X25,
|
||||
GPIO_X26,
|
||||
GPIO_X27,
|
||||
GPIO_X30,
|
||||
GPIO_X31,
|
||||
GPIO_X32,
|
||||
GPIO_X33,
|
||||
GPIO_X34,
|
||||
GPIO_X35,
|
||||
GPIO_X36,
|
||||
GPIO_X37,
|
||||
|
||||
/* GPIO_PART3_STARTS */
|
||||
GPIO_MAX_PORT_PART_2,
|
||||
GPIO_E00 = GPIO_MAX_PORT_PART_2, /* 0xc0 */
|
||||
GPIO_E01,
|
||||
GPIO_E02,
|
||||
GPIO_E03,
|
||||
GPIO_E04,
|
||||
GPIO_E05,
|
||||
GPIO_E06,
|
||||
GPIO_E07,
|
||||
GPIO_E10,
|
||||
GPIO_E11,
|
||||
GPIO_E12,
|
||||
GPIO_E13,
|
||||
GPIO_E14,
|
||||
GPIO_E15,
|
||||
GPIO_E16,
|
||||
GPIO_E17,
|
||||
GPIO_F00, /* 0xd0 */
|
||||
GPIO_F01,
|
||||
GPIO_F02,
|
||||
GPIO_F03,
|
||||
GPIO_F04,
|
||||
GPIO_F05,
|
||||
GPIO_F06,
|
||||
GPIO_F07,
|
||||
GPIO_F10,
|
||||
GPIO_F11,
|
||||
GPIO_F12,
|
||||
GPIO_F13,
|
||||
GPIO_F14,
|
||||
GPIO_F15,
|
||||
GPIO_F16,
|
||||
GPIO_F17,
|
||||
GPIO_G00,
|
||||
GPIO_G01,
|
||||
GPIO_G02,
|
||||
GPIO_G03,
|
||||
GPIO_G04,
|
||||
GPIO_G05,
|
||||
GPIO_G06,
|
||||
GPIO_G07,
|
||||
GPIO_G10,
|
||||
GPIO_G11,
|
||||
GPIO_G12,
|
||||
GPIO_G13,
|
||||
GPIO_G14,
|
||||
GPIO_G15,
|
||||
GPIO_G16,
|
||||
GPIO_G17,
|
||||
GPIO_G20,
|
||||
GPIO_G21,
|
||||
GPIO_G22,
|
||||
GPIO_G23,
|
||||
GPIO_G24,
|
||||
GPIO_G25,
|
||||
GPIO_G26,
|
||||
GPIO_G27,
|
||||
GPIO_H00,
|
||||
GPIO_H01,
|
||||
GPIO_H02,
|
||||
GPIO_H03,
|
||||
GPIO_H04,
|
||||
GPIO_H05,
|
||||
GPIO_H06,
|
||||
GPIO_H07,
|
||||
GPIO_H10,
|
||||
GPIO_H11,
|
||||
GPIO_H12,
|
||||
GPIO_H13,
|
||||
GPIO_H14,
|
||||
GPIO_H15,
|
||||
GPIO_H16,
|
||||
GPIO_H17,
|
||||
|
||||
/* GPIO_PART4_STARTS */
|
||||
GPIO_MAX_PORT_PART_3,
|
||||
GPIO_V00 = GPIO_MAX_PORT_PART_3,
|
||||
GPIO_V01,
|
||||
GPIO_V02,
|
||||
GPIO_V03,
|
||||
GPIO_V04,
|
||||
GPIO_V05,
|
||||
GPIO_V06,
|
||||
GPIO_V07,
|
||||
GPIO_V10,
|
||||
GPIO_V11,
|
||||
GPIO_V12,
|
||||
GPIO_V13,
|
||||
GPIO_V14,
|
||||
GPIO_V15,
|
||||
GPIO_V16,
|
||||
GPIO_V17,
|
||||
GPIO_V20,
|
||||
GPIO_V21,
|
||||
GPIO_V22,
|
||||
GPIO_V23,
|
||||
GPIO_V24,
|
||||
GPIO_V25,
|
||||
GPIO_V26,
|
||||
GPIO_V27,
|
||||
GPIO_V30,
|
||||
GPIO_V31,
|
||||
GPIO_V32,
|
||||
GPIO_V33,
|
||||
GPIO_V34,
|
||||
GPIO_V35,
|
||||
GPIO_V36,
|
||||
GPIO_V37,
|
||||
|
||||
/* GPIO_PART5_STARTS */
|
||||
GPIO_MAX_PORT_PART_4,
|
||||
GPIO_V40 = GPIO_MAX_PORT_PART_4,
|
||||
GPIO_V41,
|
||||
GPIO_V42,
|
||||
GPIO_V43,
|
||||
GPIO_V44,
|
||||
GPIO_V45,
|
||||
GPIO_V46,
|
||||
GPIO_V47,
|
||||
|
||||
/* GPIO_PART6_STARTS */
|
||||
GPIO_MAX_PORT_PART_5,
|
||||
GPIO_Z0 = GPIO_MAX_PORT_PART_5,
|
||||
GPIO_Z1,
|
||||
GPIO_Z2,
|
||||
GPIO_Z3,
|
||||
GPIO_Z4,
|
||||
GPIO_Z5,
|
||||
GPIO_Z6,
|
||||
GPIO_MAX_PORT
|
||||
};
|
||||
|
||||
/**
|
||||
* Set GPIO pin configuration.
|
||||
*
|
||||
* @param gpio GPIO pin
|
||||
* @param cfg Either GPIO_INPUT, GPIO_OUTPUT, or GPIO_IRQ
|
||||
*/
|
||||
void gpio_cfg_pin(int gpio, int cfg);
|
||||
|
||||
/**
|
||||
* Set GPIO pull mode.
|
||||
*
|
||||
* @param gpio GPIO pin
|
||||
* @param mode Either GPIO_PULL_DOWN or GPIO_PULL_UP
|
||||
*/
|
||||
void gpio_set_pull(int gpio, int mode);
|
||||
|
||||
/**
|
||||
* Set GPIO drive strength level.
|
||||
*
|
||||
* @param gpio GPIO pin
|
||||
* @param mode Either GPIO_DRV_1X, GPIO_DRV_2X, GPIO_DRV_3X, or GPIO_DRV_4X
|
||||
*/
|
||||
void gpio_set_drv(int gpio, int mode);
|
||||
|
||||
/**
|
||||
* Set GPIO drive rate.
|
||||
*
|
||||
* @param gpio GPIO pin
|
||||
* @param mode Either GPIO_DRV_FAST or GPIO_DRV_SLOW
|
||||
*/
|
||||
void gpio_set_rate(int gpio, int mode);
|
||||
|
||||
/*
|
||||
* reads only a single GPIO
|
||||
*
|
||||
* @param gpio GPIO to read
|
||||
* @return -1 if the value cannot be determined. Otherwise returns
|
||||
* the corresponding MVL3 enum value.
|
||||
*/
|
||||
int gpio_read_mvl3(unsigned gpio);
|
||||
|
||||
void gpio_info(void);
|
||||
|
||||
/*
|
||||
* Generic GPIO API for U-Boot
|
||||
*
|
||||
* GPIOs are numbered from 0 to GPIO_COUNT-1 which value is defined
|
||||
* by the SOC/architecture.
|
||||
*
|
||||
* Each GPIO can be an input or output. If an input then its value can
|
||||
* be read as 0 or 1. If an output then its value can be set to 0 or 1.
|
||||
* If you try to write an input then the value is undefined. If you try
|
||||
* to read an output, barring something very unusual, you will get
|
||||
* back the value of the output that you previously set.
|
||||
*
|
||||
* In some cases the operation may fail, for example if the GPIO number
|
||||
* is out of range, or the GPIO is not available because its pin is
|
||||
* being used by another function. In that case, functions may return
|
||||
* an error value of -1.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Make a GPIO an input.
|
||||
*
|
||||
* @param gpio GPIO number
|
||||
* @return 0 if ok, -1 on error
|
||||
*/
|
||||
int gpio_direction_input(unsigned gpio);
|
||||
|
||||
/**
|
||||
* Make a GPIO an output, and set its value.
|
||||
*
|
||||
* @param gpio GPIO number
|
||||
* @param value GPIO value (0 for low or 1 for high)
|
||||
* @return 0 if ok, -1 on error
|
||||
*/
|
||||
int gpio_direction_output(unsigned gpio, int value);
|
||||
|
||||
/**
|
||||
* Get a GPIO's value. This will work whether the GPIO is an input
|
||||
* or an output.
|
||||
*
|
||||
* @param gpio GPIO number
|
||||
* @return 0 if low, 1 if high, -1 on error
|
||||
*/
|
||||
int gpio_get_value(unsigned gpio);
|
||||
|
||||
/**
|
||||
* Set an output GPIO's value. The GPIO must already be an output or
|
||||
* this function may have no effect.
|
||||
*
|
||||
* @param gpio GPIO number
|
||||
* @param value GPIO value (0 for low or 1 for high)
|
||||
* @return 0 if ok, -1 on error
|
||||
*/
|
||||
int gpio_set_value(unsigned gpio, int value);
|
||||
|
||||
/*
|
||||
* Many-value logic (3 states). This can be used for inputs whereby presence
|
||||
* of external pull-up or pull-down resistors can be added to overcome internal
|
||||
* pull-ups/pull-downs and force a single value.
|
||||
*
|
||||
* Thus, external pull resistors can force a 0 or 1 and if the value changes
|
||||
* along with internal pull-up/down enable then the input is floating.
|
||||
*
|
||||
* Vpd | Vpu | MVL
|
||||
* -----------------
|
||||
* 0 | 0 | 0
|
||||
* -----------------
|
||||
* 0 | 1 | Z <-- floating input will follow internal pull up/down
|
||||
* -----------------
|
||||
* 1 | 1 | 1
|
||||
*/
|
||||
enum mvl3 {
|
||||
LOGIC_0,
|
||||
LOGIC_1,
|
||||
LOGIC_Z, /* high impedence / tri-stated / floating */
|
||||
};
|
||||
|
||||
#endif /* CPU_SAMSUNG_EXYNOS5420_GPIO_H */
|
|
@ -0,0 +1,405 @@
|
|||
/*
|
||||
* This file is part of the coreboot project.
|
||||
*
|
||||
* (C) Copyright 2002
|
||||
* David Mueller, ELSOFT AG, d.mueller@elsoft.ch
|
||||
*
|
||||
* 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; version 2 of 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include <console/console.h>
|
||||
#include <delay.h>
|
||||
#include <arch/io.h>
|
||||
#include <device/i2c.h>
|
||||
#include "clk.h"
|
||||
#include "i2c.h"
|
||||
#include "pinmux.h"
|
||||
|
||||
#define I2C_WRITE 0
|
||||
#define I2C_READ 1
|
||||
|
||||
#define I2C_OK 0
|
||||
#define I2C_NOK 1
|
||||
#define I2C_NACK 2
|
||||
#define I2C_NOK_LA 3 /* Lost arbitration */
|
||||
#define I2C_NOK_TOUT 4 /* time out */
|
||||
|
||||
#define I2CSTAT_BSY 0x20 /* Busy bit */
|
||||
#define I2CSTAT_NACK 0x01 /* Nack bit */
|
||||
#define I2CCON_ACKGEN 0x80 /* Acknowledge generation */
|
||||
#define I2CCON_IRPND 0x10 /* Interrupt pending bit */
|
||||
#define I2C_MODE_MT 0xC0 /* Master Transmit Mode */
|
||||
#define I2C_MODE_MR 0x80 /* Master Receive Mode */
|
||||
#define I2C_START_STOP 0x20 /* START / STOP */
|
||||
#define I2C_TXRX_ENA 0x10 /* I2C Tx/Rx enable */
|
||||
|
||||
/* The timeouts we live by */
|
||||
enum {
|
||||
I2C_XFER_TIMEOUT_MS = 35, /* xfer to complete */
|
||||
I2C_INIT_TIMEOUT_MS = 1000, /* bus free on init */
|
||||
I2C_IDLE_TIMEOUT_MS = 100, /* waiting for bus idle */
|
||||
I2C_STOP_TIMEOUT_US = 200, /* waiting for stop events */
|
||||
};
|
||||
|
||||
static struct s3c24x0_i2c_bus i2c_buses[] = {
|
||||
{
|
||||
.bus_num = 0,
|
||||
.regs = (struct s3c24x0_i2c *)0x12c60000,
|
||||
.periph_id = PERIPH_ID_I2C0,
|
||||
},
|
||||
{
|
||||
.bus_num = 1,
|
||||
.regs = (struct s3c24x0_i2c *)0x12c70000,
|
||||
.periph_id = PERIPH_ID_I2C1,
|
||||
},
|
||||
{
|
||||
.bus_num = 2,
|
||||
.regs = (struct s3c24x0_i2c *)0x12c80000,
|
||||
.periph_id = PERIPH_ID_I2C2,
|
||||
},
|
||||
{
|
||||
.bus_num = 3,
|
||||
.regs = (struct s3c24x0_i2c *)0x12c90000,
|
||||
.periph_id = PERIPH_ID_I2C3,
|
||||
},
|
||||
{
|
||||
.bus_num = 4,
|
||||
.regs = (struct s3c24x0_i2c *)0x12ca0000,
|
||||
.periph_id = PERIPH_ID_I2C4,
|
||||
},
|
||||
{
|
||||
.bus_num = 5,
|
||||
.regs = (struct s3c24x0_i2c *)0x12cb0000,
|
||||
.periph_id = PERIPH_ID_I2C5,
|
||||
},
|
||||
{
|
||||
.bus_num = 6,
|
||||
.regs = (struct s3c24x0_i2c *)0x12cc0000,
|
||||
.periph_id = PERIPH_ID_I2C6,
|
||||
},
|
||||
{
|
||||
.bus_num = 7,
|
||||
.regs = (struct s3c24x0_i2c *)0x12cd0000,
|
||||
.periph_id = PERIPH_ID_I2C7,
|
||||
},
|
||||
};
|
||||
|
||||
static int WaitForXfer(struct s3c24x0_i2c *i2c)
|
||||
{
|
||||
int i;
|
||||
|
||||
i = I2C_XFER_TIMEOUT_MS * 20;
|
||||
while (!(readl(&i2c->iiccon) & I2CCON_IRPND)) {
|
||||
if (i == 0) {
|
||||
printk(BIOS_ERR, "%s: i2c xfer timeout\n", __func__);
|
||||
return I2C_NOK_TOUT;
|
||||
}
|
||||
udelay(50);
|
||||
i--;
|
||||
}
|
||||
|
||||
return I2C_OK;
|
||||
}
|
||||
|
||||
static int IsACK(struct s3c24x0_i2c *i2c)
|
||||
{
|
||||
return !(readl(&i2c->iicstat) & I2CSTAT_NACK);
|
||||
}
|
||||
|
||||
static void ReadWriteByte(struct s3c24x0_i2c *i2c)
|
||||
{
|
||||
uint32_t x;
|
||||
|
||||
x = readl(&i2c->iiccon);
|
||||
writel(x & ~I2CCON_IRPND, &i2c->iiccon);
|
||||
}
|
||||
|
||||
static void i2c_ch_init(struct s3c24x0_i2c_bus *bus, int speed, int slaveadd)
|
||||
{
|
||||
unsigned long freq, pres = 16, div;
|
||||
unsigned long val;
|
||||
|
||||
freq = clock_get_periph_rate(bus->periph_id);
|
||||
/* calculate prescaler and divisor values */
|
||||
if ((freq / pres / (16 + 1)) > speed)
|
||||
/* set prescaler to 512 */
|
||||
pres = 512;
|
||||
|
||||
div = 0;
|
||||
|
||||
while ((freq / pres / (div + 1)) > speed)
|
||||
div++;
|
||||
|
||||
/* set prescaler, divisor according to freq, also set ACKGEN, IRQ */
|
||||
val = (div & 0x0F) | 0xA0 | ((pres == 512) ? 0x40 : 0);
|
||||
writel(val, &bus->regs->iiccon);
|
||||
|
||||
/* init to SLAVE RECEIVE mode and clear I2CADDn */
|
||||
writel(0, &bus->regs->iicstat);
|
||||
writel(slaveadd, &bus->regs->iicadd);
|
||||
/* program Master Transmit (and implicit STOP) */
|
||||
writel(I2C_MODE_MT | I2C_TXRX_ENA, &bus->regs->iicstat);
|
||||
}
|
||||
|
||||
/*
|
||||
* MULTI BUS I2C support
|
||||
*/
|
||||
static void i2c_bus_init(struct s3c24x0_i2c_bus *bus, int speed, int slaveadd)
|
||||
{
|
||||
exynos_pinmux_config(bus->periph_id, 0);
|
||||
i2c_ch_init(bus, speed, slaveadd);
|
||||
}
|
||||
|
||||
/*
|
||||
* Verify the whether I2C ACK was received or not
|
||||
*
|
||||
* @param i2c pointer to I2C register base
|
||||
* @param buf array of data
|
||||
* @param len length of data
|
||||
* return I2C_OK when transmission done
|
||||
* I2C_NACK otherwise
|
||||
*/
|
||||
static int i2c_send_verify(struct s3c24x0_i2c *i2c, unsigned char buf[],
|
||||
unsigned char len)
|
||||
{
|
||||
int i, result = I2C_OK;
|
||||
|
||||
if (IsACK(i2c)) {
|
||||
for (i = 0; (i < len) && (result == I2C_OK); i++) {
|
||||
writel(buf[i], &i2c->iicds);
|
||||
ReadWriteByte(i2c);
|
||||
result = WaitForXfer(i2c);
|
||||
if (result == I2C_OK && !IsACK(i2c))
|
||||
result = I2C_NACK;
|
||||
}
|
||||
} else {
|
||||
result = I2C_NACK;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void i2c_init(unsigned bus_num, int speed, int slaveadd)
|
||||
{
|
||||
struct s3c24x0_i2c_bus *i2c;
|
||||
int i;
|
||||
|
||||
i2c = &i2c_buses[bus_num];
|
||||
i2c_bus_init(i2c, speed, slaveadd);
|
||||
|
||||
/* wait for some time to give previous transfer a chance to finish */
|
||||
i = I2C_INIT_TIMEOUT_MS * 20;
|
||||
while ((readl(&i2c->regs->iicstat) & I2CSTAT_BSY) && (i > 0)) {
|
||||
udelay(50);
|
||||
i--;
|
||||
}
|
||||
|
||||
i2c_ch_init(i2c, speed, slaveadd);
|
||||
}
|
||||
|
||||
/*
|
||||
* Send a STOP event and wait for it to have completed
|
||||
*
|
||||
* @param mode If it is a master transmitter or receiver
|
||||
* @return I2C_OK if the line became idle before timeout I2C_NOK_TOUT otherwise
|
||||
*/
|
||||
static int i2c_send_stop(struct s3c24x0_i2c *i2c, int mode)
|
||||
{
|
||||
int timeout;
|
||||
|
||||
/* Setting the STOP event to fire */
|
||||
writel(mode | I2C_TXRX_ENA, &i2c->iicstat);
|
||||
ReadWriteByte(i2c);
|
||||
|
||||
/* Wait for the STOP to send and the bus to go idle */
|
||||
for (timeout = I2C_STOP_TIMEOUT_US; timeout > 0; timeout -= 5) {
|
||||
if (!(readl(&i2c->iicstat) & I2CSTAT_BSY))
|
||||
return I2C_OK;
|
||||
udelay(5);
|
||||
}
|
||||
|
||||
return I2C_NOK_TOUT;
|
||||
}
|
||||
|
||||
/*
|
||||
* cmd_type is 0 for write, 1 for read.
|
||||
*
|
||||
* addr_len can take any value from 0-255, it is only limited
|
||||
* by the char, we could make it larger if needed. If it is
|
||||
* 0 we skip the address write cycle.
|
||||
*/
|
||||
static int i2c_transfer(struct s3c24x0_i2c *i2c,
|
||||
unsigned char cmd_type,
|
||||
unsigned char chip,
|
||||
unsigned char addr[],
|
||||
unsigned char addr_len,
|
||||
unsigned char data[],
|
||||
unsigned short data_len)
|
||||
{
|
||||
int i, result, stop_bit_result;
|
||||
uint32_t x;
|
||||
|
||||
if (data == 0 || data_len == 0) {
|
||||
/* Don't support data transfer of no length or to address 0 */
|
||||
printk(BIOS_ERR, "i2c_transfer: bad call\n");
|
||||
return I2C_NOK;
|
||||
}
|
||||
|
||||
/* Check I2C bus idle */
|
||||
i = I2C_IDLE_TIMEOUT_MS * 20;
|
||||
while ((readl(&i2c->iicstat) & I2CSTAT_BSY) && (i > 0)) {
|
||||
udelay(50);
|
||||
i--;
|
||||
}
|
||||
|
||||
if (readl(&i2c->iicstat) & I2CSTAT_BSY) {
|
||||
printk(BIOS_ERR, "%s: bus busy\n", __func__);
|
||||
return I2C_NOK_TOUT;
|
||||
}
|
||||
|
||||
x = readl(&i2c->iiccon);
|
||||
writel(x | I2CCON_ACKGEN, &i2c->iiccon);
|
||||
|
||||
if (addr && addr_len) {
|
||||
writel(chip, &i2c->iicds);
|
||||
/* send START */
|
||||
writel(I2C_MODE_MT | I2C_TXRX_ENA | I2C_START_STOP,
|
||||
&i2c->iicstat);
|
||||
if (WaitForXfer(i2c) == I2C_OK)
|
||||
result = i2c_send_verify(i2c, addr, addr_len);
|
||||
else
|
||||
result = I2C_NACK;
|
||||
} else
|
||||
result = I2C_NACK;
|
||||
|
||||
switch (cmd_type) {
|
||||
case I2C_WRITE:
|
||||
if (result == I2C_OK)
|
||||
result = i2c_send_verify(i2c, data, data_len);
|
||||
else {
|
||||
writel(chip, &i2c->iicds);
|
||||
/* send START */
|
||||
writel(I2C_MODE_MT | I2C_TXRX_ENA | I2C_START_STOP,
|
||||
&i2c->iicstat);
|
||||
if (WaitForXfer(i2c) == I2C_OK)
|
||||
result = i2c_send_verify(i2c, data, data_len);
|
||||
}
|
||||
|
||||
if (result == I2C_OK)
|
||||
result = WaitForXfer(i2c);
|
||||
|
||||
stop_bit_result = i2c_send_stop(i2c, I2C_MODE_MT);
|
||||
break;
|
||||
|
||||
case I2C_READ:
|
||||
{
|
||||
int was_ok = (result == I2C_OK);
|
||||
|
||||
writel(chip, &i2c->iicds);
|
||||
/* resend START */
|
||||
writel(I2C_MODE_MR | I2C_TXRX_ENA |
|
||||
I2C_START_STOP, &i2c->iicstat);
|
||||
ReadWriteByte(i2c);
|
||||
result = WaitForXfer(i2c);
|
||||
|
||||
if (was_ok || IsACK(i2c)) {
|
||||
i = 0;
|
||||
while ((i < data_len) && (result == I2C_OK)) {
|
||||
/* disable ACK for final READ */
|
||||
if (i == data_len - 1) {
|
||||
x = readl(&i2c->iiccon) & ~I2CCON_ACKGEN;
|
||||
writel(x, &i2c->iiccon);
|
||||
}
|
||||
ReadWriteByte(i2c);
|
||||
result = WaitForXfer(i2c);
|
||||
data[i] = readl(&i2c->iicds);
|
||||
i++;
|
||||
}
|
||||
} else {
|
||||
result = I2C_NACK;
|
||||
}
|
||||
|
||||
stop_bit_result = i2c_send_stop(i2c, I2C_MODE_MR);
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
printk(BIOS_ERR, "i2c_transfer: bad call\n");
|
||||
result = stop_bit_result = I2C_NOK;
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
* If the transmission went fine, then only the stop bit was left to
|
||||
* fail. Otherwise, the real failure we're interested in came before
|
||||
* that, during the actual transmission.
|
||||
*/
|
||||
return (result == I2C_OK) ? stop_bit_result : result;
|
||||
}
|
||||
|
||||
int i2c_read(unsigned bus, unsigned chip, unsigned addr,
|
||||
unsigned alen, unsigned char *buf, unsigned len)
|
||||
{
|
||||
struct s3c24x0_i2c_bus *i2c;
|
||||
unsigned char xaddr[4];
|
||||
int ret;
|
||||
|
||||
if (alen > 4) {
|
||||
printk(BIOS_ERR, "I2C read: addr len %d not supported\n", alen);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (alen > 0) {
|
||||
xaddr[0] = (addr >> 24) & 0xFF;
|
||||
xaddr[1] = (addr >> 16) & 0xFF;
|
||||
xaddr[2] = (addr >> 8) & 0xFF;
|
||||
xaddr[3] = addr & 0xFF;
|
||||
}
|
||||
|
||||
i2c = &i2c_buses[bus];
|
||||
ret = i2c_transfer(i2c->regs, I2C_READ, chip << 1, &xaddr[4 - alen],
|
||||
alen, buf, len);
|
||||
if (ret) {
|
||||
printk(BIOS_ERR, "I2c read: failed %d\n", ret);
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int i2c_write(unsigned bus, unsigned chip, unsigned addr,
|
||||
unsigned alen, unsigned char *buf, unsigned len)
|
||||
{
|
||||
struct s3c24x0_i2c_bus *i2c;
|
||||
unsigned char xaddr[4];
|
||||
int ret;
|
||||
|
||||
if (alen > 4) {
|
||||
printk(BIOS_ERR, "I2C write: addr len %d not supported\n",
|
||||
alen);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (alen > 0) {
|
||||
xaddr[0] = (addr >> 24) & 0xFF;
|
||||
xaddr[1] = (addr >> 16) & 0xFF;
|
||||
xaddr[2] = (addr >> 8) & 0xFF;
|
||||
xaddr[3] = addr & 0xFF;
|
||||
}
|
||||
|
||||
i2c = &i2c_buses[bus];
|
||||
ret = i2c_transfer(i2c->regs, I2C_WRITE, chip << 1, &xaddr[4 - alen],
|
||||
alen, buf, len);
|
||||
|
||||
return ret != 0;
|
||||
}
|
|
@ -0,0 +1,41 @@
|
|||
/*
|
||||
* This file is part of the coreboot project.
|
||||
*
|
||||
* Copyright (C) 2012 Samsung Electronics
|
||||
*
|
||||
* 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; version 2 of 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#ifndef CPU_SAMSUNG_EXYNOS5420_I2C_H
|
||||
#define CPU_SAMSUNG_EXYNOS5420_I2C_H
|
||||
|
||||
#include "periph.h"
|
||||
|
||||
struct s3c24x0_i2c {
|
||||
u32 iiccon;
|
||||
u32 iicstat;
|
||||
u32 iicadd;
|
||||
u32 iicds;
|
||||
u32 iiclc;
|
||||
};
|
||||
|
||||
struct s3c24x0_i2c_bus {
|
||||
int bus_num;
|
||||
struct s3c24x0_i2c *regs;
|
||||
enum periph_id periph_id;
|
||||
};
|
||||
|
||||
void i2c_init(unsigned bus, int speed, int slaveadd);
|
||||
|
||||
#endif /* CPU_SAMSUNG_EXYNOS5420_I2C_H */
|
|
@ -0,0 +1,142 @@
|
|||
/*
|
||||
* This file is part of the coreboot project.
|
||||
*
|
||||
* Copyright (C) 2012 Samsung Electronics
|
||||
*
|
||||
* 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; version 2 of 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
/* Taken from the kernel code */
|
||||
|
||||
#ifndef CPU_SAMSUNG_EXYNOS5420_I2S_REGS_H
|
||||
#define CPU_SAMSUNG_EXYNOS5420_I2S_REGS_H
|
||||
|
||||
#define I2SCON 0x0
|
||||
#define I2SMOD 0x4
|
||||
#define I2SFIC 0x8
|
||||
#define I2SPSR 0xc
|
||||
#define I2STXD 0x10
|
||||
#define I2SRXD 0x14
|
||||
#define I2SFICS 0x18
|
||||
#define I2STXDS 0x1c
|
||||
#define I2SAHB 0x20
|
||||
#define I2SSTR0 0x24
|
||||
#define I2SSIZE 0x28
|
||||
#define I2STRNCNT 0x2c
|
||||
#define I2SLVL0ADDR 0x30
|
||||
#define I2SLVL1ADDR 0x34
|
||||
#define I2SLVL2ADDR 0x38
|
||||
#define I2SLVL3ADDR 0x3c
|
||||
|
||||
#define CON_RSTCLR (1 << 31)
|
||||
#define CON_FRXOFSTATUS (1 << 26)
|
||||
#define CON_FRXORINTEN (1 << 25)
|
||||
#define CON_FTXSURSTAT (1 << 24)
|
||||
#define CON_FTXSURINTEN (1 << 23)
|
||||
#define CON_TXSDMA_PAUSE (1 << 20)
|
||||
#define CON_TXSDMA_ACTIVE (1 << 18)
|
||||
|
||||
#define CON_FTXURSTATUS (1 << 17)
|
||||
#define CON_FTXURINTEN (1 << 16)
|
||||
#define CON_TXFIFO2_EMPTY (1 << 15)
|
||||
#define CON_TXFIFO1_EMPTY (1 << 14)
|
||||
#define CON_TXFIFO2_FULL (1 << 13)
|
||||
#define CON_TXFIFO1_FULL (1 << 12)
|
||||
|
||||
#define CON_LRINDEX (1 << 11)
|
||||
#define CON_TXFIFO_EMPTY (1 << 10)
|
||||
#define CON_RXFIFO_EMPTY (1 << 9)
|
||||
#define CON_TXFIFO_FULL (1 << 8)
|
||||
#define CON_RXFIFO_FULL (1 << 7)
|
||||
#define CON_TXDMA_PAUSE (1 << 6)
|
||||
#define CON_RXDMA_PAUSE (1 << 5)
|
||||
#define CON_TXCH_PAUSE (1 << 4)
|
||||
#define CON_RXCH_PAUSE (1 << 3)
|
||||
#define CON_TXDMA_ACTIVE (1 << 2)
|
||||
#define CON_RXDMA_ACTIVE (1 << 1)
|
||||
#define CON_ACTIVE (1 << 0)
|
||||
|
||||
#define MOD_OPCLK_CDCLK_OUT (0 << 30)
|
||||
#define MOD_OPCLK_CDCLK_IN (1 << 30)
|
||||
#define MOD_OPCLK_BCLK_OUT (2 << 30)
|
||||
#define MOD_OPCLK_PCLK (3 << 30)
|
||||
#define MOD_OPCLK_MASK (3 << 30)
|
||||
#define MOD_TXS_IDMA (1 << 28) /* Sec_TXFIFO use I-DMA */
|
||||
|
||||
#define MOD_BLCS_SHIFT 26
|
||||
#define MOD_BLCS_16BIT (0 << MOD_BLCS_SHIFT)
|
||||
#define MOD_BLCS_8BIT (1 << MOD_BLCS_SHIFT)
|
||||
#define MOD_BLCS_24BIT (2 << MOD_BLCS_SHIFT)
|
||||
#define MOD_BLCS_MASK (3 << MOD_BLCS_SHIFT)
|
||||
|
||||
#define MOD_BLCP_SHIFT 24
|
||||
#define MOD_BLCP_16BIT (0 << MOD_BLCP_SHIFT)
|
||||
#define MOD_BLCP_8BIT (1 << MOD_BLCP_SHIFT)
|
||||
#define MOD_BLCP_24BIT (2 << MOD_BLCP_SHIFT)
|
||||
#define MOD_BLCP_MASK (3 << MOD_BLCP_SHIFT)
|
||||
|
||||
#define MOD_C2DD_HHALF (1 << 21) /* Discard Higher-half */
|
||||
#define MOD_C2DD_LHALF (1 << 20) /* Discard Lower-half */
|
||||
#define MOD_C1DD_HHALF (1 << 19)
|
||||
#define MOD_C1DD_LHALF (1 << 18)
|
||||
#define MOD_DC2_EN (1 << 17)
|
||||
#define MOD_DC1_EN (1 << 16)
|
||||
#define MOD_BLC_16BIT (0 << 13)
|
||||
#define MOD_BLC_8BIT (1 << 13)
|
||||
#define MOD_BLC_24BIT (2 << 13)
|
||||
#define MOD_BLC_MASK (3 << 13)
|
||||
|
||||
#define MOD_IMS_SYSMUX (1 << 10)
|
||||
#define MOD_SLAVE (1 << 11)
|
||||
#define MOD_TXONLY (0 << 8)
|
||||
#define MOD_RXONLY (1 << 8)
|
||||
#define MOD_TXRX (2 << 8)
|
||||
#define MOD_MASK (3 << 8)
|
||||
#define MOD_LR_LLOW (0 << 7)
|
||||
#define MOD_LR_RLOW (1 << 7)
|
||||
#define MOD_SDF_IIS (0 << 5)
|
||||
#define MOD_SDF_MSB (1 << 5)
|
||||
#define MOD_SDF_LSB (2 << 5)
|
||||
#define MOD_SDF_MASK (3 << 5)
|
||||
#define MOD_RCLK_256FS (0 << 3)
|
||||
#define MOD_RCLK_512FS (1 << 3)
|
||||
#define MOD_RCLK_384FS (2 << 3)
|
||||
#define MOD_RCLK_768FS (3 << 3)
|
||||
#define MOD_RCLK_MASK (3 << 3)
|
||||
#define MOD_BCLK_32FS (0 << 1)
|
||||
#define MOD_BCLK_48FS (1 << 1)
|
||||
#define MOD_BCLK_16FS (2 << 1)
|
||||
#define MOD_BCLK_24FS (3 << 1)
|
||||
#define MOD_BCLK_MASK (3 << 1)
|
||||
#define MOD_8BIT (1 << 0)
|
||||
|
||||
#define MOD_CDCLKCON (1 << 12)
|
||||
|
||||
#define PSR_PSREN (1 << 15)
|
||||
|
||||
#define FIC_TXFLUSH (1 << 15)
|
||||
#define FIC_RXFLUSH (1 << 7)
|
||||
|
||||
#define AHB_INTENLVL0 (1 << 24)
|
||||
#define AHB_LVL0INT (1 << 20)
|
||||
#define AHB_CLRLVL0INT (1 << 16)
|
||||
#define AHB_DMARLD (1 << 5)
|
||||
#define AHB_INTMASK (1 << 3)
|
||||
#define AHB_DMAEN (1 << 0)
|
||||
#define AHB_LVLINTMASK (0xf << 20)
|
||||
|
||||
#define I2SSIZE_TRNMSK (0xffff)
|
||||
#define I2SSIZE_SHIFT (16)
|
||||
|
||||
#endif /* CPU_SAMSUNG_EXYNOS5420_I2S_REGS_H */
|
|
@ -0,0 +1,104 @@
|
|||
/*
|
||||
* This file is part of the coreboot project.
|
||||
*
|
||||
* Copyright 2012 Google Inc.
|
||||
*
|
||||
* 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; version 2 of 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <arch/io.h>
|
||||
#include "clk.h"
|
||||
|
||||
struct __attribute__((packed)) mct_regs
|
||||
{
|
||||
uint32_t mct_cfg;
|
||||
uint8_t reserved0[0xfc];
|
||||
uint32_t g_cnt_l;
|
||||
uint32_t g_cnt_u;
|
||||
uint8_t reserved1[0x8];
|
||||
uint32_t g_cnt_wstat;
|
||||
uint8_t reserved2[0xec];
|
||||
uint32_t g_comp0_l;
|
||||
uint32_t g_comp0_u;
|
||||
uint32_t g_comp0_addr_incr;
|
||||
uint8_t reserved3[0x4];
|
||||
uint32_t g_comp1_l;
|
||||
uint32_t g_comp1_u;
|
||||
uint32_t g_comp1_addr_incr;
|
||||
uint8_t reserved4[0x4];
|
||||
uint32_t g_comp2_l;
|
||||
uint32_t g_comp2_u;
|
||||
uint32_t g_comp2_addr_incr;
|
||||
uint8_t reserved5[0x4];
|
||||
uint32_t g_comp3_l;
|
||||
uint32_t g_comp3_u;
|
||||
uint32_t g_comp3_addr_incr;
|
||||
uint8_t reserved6[0x4];
|
||||
uint32_t g_tcon;
|
||||
uint32_t g_int_cstat;
|
||||
uint32_t g_int_enb;
|
||||
uint32_t g_wstat;
|
||||
uint8_t reserved7[0xb0];
|
||||
uint32_t l0_tcntb;
|
||||
uint32_t l0_tcnto;
|
||||
uint32_t l0_icntb;
|
||||
uint32_t l0_icnto;
|
||||
uint32_t l0_frcntb;
|
||||
uint32_t l0_frcnto;
|
||||
uint8_t reserved8[0x8];
|
||||
uint32_t l0_tcon;
|
||||
uint8_t reserved9[0xc];
|
||||
uint32_t l0_int_cstat;
|
||||
uint32_t l0_int_enb;
|
||||
uint8_t reserved10[0x8];
|
||||
uint32_t l0_wstat;
|
||||
uint8_t reserved11[0xbc];
|
||||
uint32_t l1_tcntb;
|
||||
uint32_t l1_tcnto;
|
||||
uint32_t l1_icntb;
|
||||
uint32_t l1_icnto;
|
||||
uint32_t l1_frcntb;
|
||||
uint32_t l1_frcnto;
|
||||
uint8_t reserved12[0x8];
|
||||
uint32_t l1_tcon;
|
||||
uint8_t reserved13[0xc];
|
||||
uint32_t l1_int_cstat;
|
||||
uint32_t l1_int_enb;
|
||||
uint8_t reserved14[0x8];
|
||||
uint32_t l1_wstat;
|
||||
};
|
||||
|
||||
static int enabled = 0;
|
||||
static struct mct_regs *const mct =
|
||||
(struct mct_regs *)MCT_ADDRESS;
|
||||
|
||||
uint64_t mct_raw_value(void)
|
||||
{
|
||||
if (!enabled) {
|
||||
writel(readl(&mct->g_tcon) | (0x1 << 8), &mct->g_tcon);
|
||||
enabled = 1;
|
||||
}
|
||||
|
||||
uint64_t upper = readl(&mct->g_cnt_u);
|
||||
uint64_t lower = readl(&mct->g_cnt_l);
|
||||
|
||||
return (upper << 32) | lower;
|
||||
}
|
||||
|
||||
void mct_start(void)
|
||||
{
|
||||
writel(readl(&mct->g_tcon) | (0x1 << 8), &mct->g_tcon);
|
||||
enabled = 1;
|
||||
}
|
|
@ -0,0 +1,57 @@
|
|||
/*
|
||||
* This file is part of the coreboot project.
|
||||
*
|
||||
* Copyright 2013 Google Inc.
|
||||
*
|
||||
* 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; version 2 of 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <delay.h>
|
||||
#include <timer.h>
|
||||
|
||||
#include "clk.h"
|
||||
|
||||
static struct monotonic_counter {
|
||||
int initialized;
|
||||
struct mono_time time;
|
||||
uint64_t last_value;
|
||||
} mono_counter;
|
||||
|
||||
static const uint32_t clocks_per_usec = MCT_HZ/1000000;
|
||||
|
||||
void timer_monotonic_get(struct mono_time *mt)
|
||||
{
|
||||
uint64_t current_tick;
|
||||
uint64_t usecs_elapsed;
|
||||
|
||||
if (!mono_counter.initialized) {
|
||||
init_timer();
|
||||
mono_counter.last_value = mct_raw_value();
|
||||
mono_counter.initialized = 1;
|
||||
}
|
||||
|
||||
current_tick = mct_raw_value();
|
||||
usecs_elapsed = (current_tick - mono_counter.last_value) /
|
||||
clocks_per_usec;
|
||||
|
||||
/* Update current time and tick values only if a full tick occurred. */
|
||||
if (usecs_elapsed) {
|
||||
mono_time_add_usecs(&mono_counter.time, usecs_elapsed);
|
||||
mono_counter.last_value = current_tick;
|
||||
}
|
||||
|
||||
/* Save result. */
|
||||
*mt = mono_counter.time;
|
||||
}
|
|
@ -0,0 +1,69 @@
|
|||
/*
|
||||
* This file is part of the coreboot project.
|
||||
*
|
||||
* Copyright 2012 Google Inc.
|
||||
*
|
||||
* 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; version 2 of 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#ifndef CPU_SAMSUNG_EXYNOS5420_PERIPH_H
|
||||
#define CPU_SAMSUNG_EXYNOS5420_PERIPH_H
|
||||
|
||||
/*
|
||||
* Peripherals requiring clock/pinmux configuration. List will
|
||||
* grow with support for more devices getting added.
|
||||
*
|
||||
* At present the order is arbitrary - we may be able to take advantage
|
||||
* of some orthogonality later.
|
||||
*/
|
||||
enum periph_id {
|
||||
PERIPH_ID_UART0,
|
||||
PERIPH_ID_UART1,
|
||||
PERIPH_ID_UART2,
|
||||
PERIPH_ID_UART3,
|
||||
PERIPH_ID_SDMMC0,
|
||||
PERIPH_ID_SDMMC1,
|
||||
PERIPH_ID_SDMMC2,
|
||||
PERIPH_ID_SDMMC3,
|
||||
|
||||
PERIPH_ID_SROMC = 9,
|
||||
PERIPH_ID_SPI0,
|
||||
PERIPH_ID_SPI1,
|
||||
PERIPH_ID_SPI2,
|
||||
PERIPH_ID_SPI3,
|
||||
PERIPH_ID_SPI4,
|
||||
PERIPH_ID_LCD,
|
||||
PERIPH_ID_BACKLIGHT,
|
||||
PERIPH_ID_I2C0,
|
||||
PERIPH_ID_I2C1,
|
||||
PERIPH_ID_I2C2,
|
||||
PERIPH_ID_I2C3,
|
||||
PERIPH_ID_I2C4,
|
||||
PERIPH_ID_I2C5,
|
||||
PERIPH_ID_I2C6,
|
||||
PERIPH_ID_I2C7,
|
||||
PERIPH_ID_DPHPD, /* eDP hot plug detect */
|
||||
PERIPH_ID_PWM0,
|
||||
PERIPH_ID_PWM1,
|
||||
PERIPH_ID_PWM2,
|
||||
PERIPH_ID_PWM3,
|
||||
PERIPH_ID_PWM4,
|
||||
PERIPH_ID_I2S1,
|
||||
PERIPH_ID_SATA,
|
||||
|
||||
PERIPH_ID_COUNT,
|
||||
PERIPH_ID_NONE = -1,
|
||||
};
|
||||
|
||||
#endif
|
|
@ -0,0 +1,298 @@
|
|||
/*
|
||||
* This file is part of the coreboot project.
|
||||
*
|
||||
* Copyright (C) 2012 Samsung Electronics
|
||||
*
|
||||
* 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; version 2 of 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include <console/console.h>
|
||||
#include <assert.h>
|
||||
#include "gpio.h"
|
||||
#include "cpu.h"
|
||||
#include "pinmux.h"
|
||||
|
||||
int exynos_pinmux_config(enum periph_id peripheral, int flags)
|
||||
{
|
||||
int i, start, count, start_ext, pin_ext, pin, drv;
|
||||
|
||||
switch (peripheral) {
|
||||
case PERIPH_ID_UART0:
|
||||
case PERIPH_ID_UART1:
|
||||
case PERIPH_ID_UART2:
|
||||
case PERIPH_ID_UART3:
|
||||
switch (peripheral) {
|
||||
default:
|
||||
case PERIPH_ID_UART0:
|
||||
start = GPIO_A00; count = 4;
|
||||
break;
|
||||
case PERIPH_ID_UART1:
|
||||
start = GPIO_A04; count = 4;
|
||||
break;
|
||||
case PERIPH_ID_UART2:
|
||||
start = GPIO_A10; count = 4;
|
||||
break;
|
||||
case PERIPH_ID_UART3:
|
||||
start = GPIO_A14; count = 2;
|
||||
break;
|
||||
}
|
||||
for (i = start; i < start + count; i++) {
|
||||
gpio_set_pull(i, GPIO_PULL_NONE);
|
||||
gpio_cfg_pin(i, GPIO_FUNC(0x2));
|
||||
}
|
||||
break;
|
||||
case PERIPH_ID_SDMMC0:
|
||||
case PERIPH_ID_SDMMC1:
|
||||
case PERIPH_ID_SDMMC2:
|
||||
case PERIPH_ID_SDMMC3:
|
||||
pin = GPIO_FUNC(0x2);
|
||||
pin_ext = GPIO_FUNC(0x2);
|
||||
drv = GPIO_DRV_4X;
|
||||
switch (peripheral) {
|
||||
default:
|
||||
case PERIPH_ID_SDMMC0:
|
||||
start = GPIO_C00;
|
||||
start_ext = GPIO_C10;
|
||||
break;
|
||||
case PERIPH_ID_SDMMC1:
|
||||
start = GPIO_C20;
|
||||
start_ext = 0;
|
||||
break;
|
||||
case PERIPH_ID_SDMMC2:
|
||||
start = GPIO_C30;
|
||||
/*
|
||||
* TODO: (alim.akhtar@samsung.com)
|
||||
* add support for 8 bit mode (needs to be a per-board
|
||||
* option, so in the FDT).
|
||||
*/
|
||||
start_ext = 0;
|
||||
break;
|
||||
case PERIPH_ID_SDMMC3:
|
||||
/*
|
||||
* TODO: Need to add defintions for GPC4 before
|
||||
* enabling this.
|
||||
*/
|
||||
printk(BIOS_DEBUG, "SDMMC3 not supported yet");
|
||||
return -1;
|
||||
}
|
||||
if ((flags & PINMUX_FLAG_8BIT_MODE) && !start_ext) {
|
||||
printk(BIOS_DEBUG, "SDMMC device %d does not support 8bit mode",
|
||||
peripheral);
|
||||
return -1;
|
||||
}
|
||||
if (flags & PINMUX_FLAG_8BIT_MODE) {
|
||||
ASSERT(peripheral == PERIPH_ID_SDMMC0);
|
||||
for (i = 0; i <= 3; i++) {
|
||||
gpio_cfg_pin(start_ext + i, pin_ext);
|
||||
gpio_set_pull(start_ext + i,
|
||||
GPIO_PULL_UP);
|
||||
gpio_set_drv(start_ext + i, drv);
|
||||
}
|
||||
}
|
||||
for (i = 0; i < 2; i++) {
|
||||
gpio_cfg_pin(start + i, pin);
|
||||
gpio_set_pull(start + i, GPIO_PULL_NONE);
|
||||
gpio_set_drv(start + i, drv);
|
||||
}
|
||||
for (i = 2; i <= 6; i++) {
|
||||
gpio_cfg_pin(start + i, pin);
|
||||
gpio_set_pull(start + i, GPIO_PULL_UP);
|
||||
gpio_set_drv(start + i, drv);
|
||||
}
|
||||
break;
|
||||
case PERIPH_ID_SROMC:
|
||||
/*
|
||||
* SROM:CS1 and EBI
|
||||
*
|
||||
* GPY0[0] SROM_CSn[0]
|
||||
* GPY0[1] SROM_CSn[1](2)
|
||||
* GPY0[2] SROM_CSn[2]
|
||||
* GPY0[3] SROM_CSn[3]
|
||||
* GPY0[4] EBI_OEn(2)
|
||||
* GPY0[5] EBI_EEn(2)
|
||||
*
|
||||
* GPY1[0] EBI_BEn[0](2)
|
||||
* GPY1[1] EBI_BEn[1](2)
|
||||
* GPY1[2] SROM_WAIT(2)
|
||||
* GPY1[3] EBI_DATA_RDn(2)
|
||||
*/
|
||||
gpio_cfg_pin(GPIO_Y00 + (flags & PINMUX_FLAG_BANK),
|
||||
GPIO_FUNC(2));
|
||||
gpio_cfg_pin(GPIO_Y04, GPIO_FUNC(2));
|
||||
gpio_cfg_pin(GPIO_Y05, GPIO_FUNC(2));
|
||||
|
||||
for (i = 2; i < 4; i++)
|
||||
gpio_cfg_pin(GPIO_Y10 + i, GPIO_FUNC(2));
|
||||
|
||||
/*
|
||||
* EBI: 8 Addrss Lines
|
||||
*
|
||||
* GPY3[0] EBI_ADDR[0](2)
|
||||
* GPY3[1] EBI_ADDR[1](2)
|
||||
* GPY3[2] EBI_ADDR[2](2)
|
||||
* GPY3[3] EBI_ADDR[3](2)
|
||||
* GPY3[4] EBI_ADDR[4](2)
|
||||
* GPY3[5] EBI_ADDR[5](2)
|
||||
* GPY3[6] EBI_ADDR[6](2)
|
||||
* GPY3[7] EBI_ADDR[7](2)
|
||||
*
|
||||
* EBI: 16 Data Lines
|
||||
*
|
||||
* GPY5[0] EBI_DATA[0](2)
|
||||
* GPY5[1] EBI_DATA[1](2)
|
||||
* GPY5[2] EBI_DATA[2](2)
|
||||
* GPY5[3] EBI_DATA[3](2)
|
||||
* GPY5[4] EBI_DATA[4](2)
|
||||
* GPY5[5] EBI_DATA[5](2)
|
||||
* GPY5[6] EBI_DATA[6](2)
|
||||
* GPY5[7] EBI_DATA[7](2)
|
||||
*
|
||||
* GPY6[0] EBI_DATA[8](2)
|
||||
* GPY6[1] EBI_DATA[9](2)
|
||||
* GPY6[2] EBI_DATA[10](2)
|
||||
* GPY6[3] EBI_DATA[11](2)
|
||||
* GPY6[4] EBI_DATA[12](2)
|
||||
* GPY6[5] EBI_DATA[13](2)
|
||||
* GPY6[6] EBI_DATA[14](2)
|
||||
* GPY6[7] EBI_DATA[15](2)
|
||||
*/
|
||||
for (i = 0; i < 8; i++) {
|
||||
gpio_cfg_pin(GPIO_Y30 + i, GPIO_FUNC(2));
|
||||
gpio_set_pull(GPIO_Y30 + i, GPIO_PULL_UP);
|
||||
|
||||
gpio_cfg_pin(GPIO_Y50 + i, GPIO_FUNC(2));
|
||||
gpio_set_pull(GPIO_Y50 + i, GPIO_PULL_UP);
|
||||
|
||||
if (flags & PINMUX_FLAG_16BIT) {
|
||||
gpio_cfg_pin(GPIO_Y60 + i, GPIO_FUNC(2));
|
||||
gpio_set_pull(GPIO_Y60 + i,
|
||||
GPIO_PULL_UP);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case PERIPH_ID_SPI0:
|
||||
case PERIPH_ID_SPI1:
|
||||
case PERIPH_ID_SPI2:
|
||||
case PERIPH_ID_SPI3: {
|
||||
int cfg;
|
||||
|
||||
switch (peripheral) {
|
||||
default:
|
||||
case PERIPH_ID_SPI0:
|
||||
start = GPIO_A20;
|
||||
cfg = 0x2;
|
||||
break;
|
||||
case PERIPH_ID_SPI1:
|
||||
start = GPIO_A24;
|
||||
cfg = 0x2;
|
||||
break;
|
||||
case PERIPH_ID_SPI2:
|
||||
start = GPIO_B11;
|
||||
cfg = 0x5;
|
||||
break;
|
||||
case PERIPH_ID_SPI3:
|
||||
start = GPIO_E00;
|
||||
cfg = 0x2;
|
||||
break;
|
||||
}
|
||||
|
||||
for (i = 0; i < 4; i++)
|
||||
gpio_cfg_pin(start + i, GPIO_FUNC(cfg));
|
||||
break;
|
||||
}
|
||||
case PERIPH_ID_SPI4:
|
||||
for (i = 0; i < 2; i++)
|
||||
gpio_cfg_pin(GPIO_F02 + i, GPIO_FUNC(0x4));
|
||||
for (i = 2; i < 4; i++)
|
||||
gpio_cfg_pin(GPIO_E02 + i, GPIO_FUNC(0x4));
|
||||
break;
|
||||
case PERIPH_ID_BACKLIGHT:
|
||||
gpio_cfg_pin(GPIO_B20, GPIO_OUTPUT);
|
||||
gpio_set_value(GPIO_B20, 1);
|
||||
break;
|
||||
case PERIPH_ID_LCD:
|
||||
gpio_cfg_pin(GPIO_Y25, GPIO_OUTPUT);
|
||||
gpio_set_value(GPIO_Y25, 1);
|
||||
gpio_cfg_pin(GPIO_X15, GPIO_OUTPUT);
|
||||
gpio_set_value(GPIO_X15, 1);
|
||||
gpio_cfg_pin(GPIO_X30, GPIO_OUTPUT);
|
||||
gpio_set_value(GPIO_X30, 1);
|
||||
break;
|
||||
case PERIPH_ID_I2C0:
|
||||
gpio_cfg_pin(GPIO_B30, GPIO_FUNC(0x2));
|
||||
gpio_cfg_pin(GPIO_B31, GPIO_FUNC(0x2));
|
||||
gpio_set_pull(GPIO_B30, GPIO_PULL_NONE);
|
||||
gpio_set_pull(GPIO_B31, GPIO_PULL_NONE);
|
||||
break;
|
||||
case PERIPH_ID_I2C1:
|
||||
gpio_cfg_pin(GPIO_B32, GPIO_FUNC(0x2));
|
||||
gpio_cfg_pin(GPIO_B33, GPIO_FUNC(0x2));
|
||||
gpio_set_pull(GPIO_B32, GPIO_PULL_NONE);
|
||||
gpio_set_pull(GPIO_B33, GPIO_PULL_NONE);
|
||||
break;
|
||||
case PERIPH_ID_I2C2:
|
||||
gpio_cfg_pin(GPIO_A06, GPIO_FUNC(0x3));
|
||||
gpio_cfg_pin(GPIO_A07, GPIO_FUNC(0x3));
|
||||
gpio_set_pull(GPIO_A06, GPIO_PULL_NONE);
|
||||
gpio_set_pull(GPIO_A07, GPIO_PULL_NONE);
|
||||
break;
|
||||
case PERIPH_ID_I2C3:
|
||||
gpio_cfg_pin(GPIO_A12, GPIO_FUNC(0x3));
|
||||
gpio_cfg_pin(GPIO_A13, GPIO_FUNC(0x3));
|
||||
gpio_set_pull(GPIO_A12, GPIO_PULL_NONE);
|
||||
gpio_set_pull(GPIO_A13, GPIO_PULL_NONE);
|
||||
break;
|
||||
case PERIPH_ID_I2C4:
|
||||
gpio_cfg_pin(GPIO_A20, GPIO_FUNC(0x3));
|
||||
gpio_cfg_pin(GPIO_A21, GPIO_FUNC(0x3));
|
||||
gpio_set_pull(GPIO_A20, GPIO_PULL_NONE);
|
||||
gpio_set_pull(GPIO_A21, GPIO_PULL_NONE);
|
||||
break;
|
||||
case PERIPH_ID_I2C5:
|
||||
gpio_cfg_pin(GPIO_A22, GPIO_FUNC(0x3));
|
||||
gpio_cfg_pin(GPIO_A23, GPIO_FUNC(0x3));
|
||||
gpio_set_pull(GPIO_A22, GPIO_PULL_NONE);
|
||||
gpio_set_pull(GPIO_A23, GPIO_PULL_NONE);
|
||||
break;
|
||||
case PERIPH_ID_I2C6:
|
||||
gpio_cfg_pin(GPIO_B13, GPIO_FUNC(0x4));
|
||||
gpio_cfg_pin(GPIO_B14, GPIO_FUNC(0x4));
|
||||
break;
|
||||
case PERIPH_ID_I2C7:
|
||||
gpio_cfg_pin(GPIO_B22, GPIO_FUNC(0x3));
|
||||
gpio_cfg_pin(GPIO_B23, GPIO_FUNC(0x3));
|
||||
gpio_set_pull(GPIO_B22, GPIO_PULL_NONE);
|
||||
gpio_set_pull(GPIO_B23, GPIO_PULL_NONE);
|
||||
break;
|
||||
case PERIPH_ID_DPHPD:
|
||||
/* Set Hotplug detect for DP */
|
||||
gpio_cfg_pin(GPIO_X07, GPIO_FUNC(0x3));
|
||||
|
||||
/*
|
||||
* Hotplug detect should have an external pullup; disable the
|
||||
* internal pulldown so they don't fight.
|
||||
*/
|
||||
gpio_set_pull(GPIO_X07, GPIO_PULL_NONE);
|
||||
break;
|
||||
case PERIPH_ID_I2S1:
|
||||
for (i = 0; i < 5; i++)
|
||||
gpio_cfg_pin(GPIO_B00 + i, GPIO_FUNC(0x02));
|
||||
break;
|
||||
default:
|
||||
printk(BIOS_DEBUG, "%s: invalid peripheral %d", __func__, peripheral);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,55 @@
|
|||
/*
|
||||
* This file is part of the coreboot project.
|
||||
*
|
||||
* Copyright (C) 2012 Samsung Electronics
|
||||
*
|
||||
* 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; version 2 of 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#ifndef CPU_SAMSUNG_EXYNOS5420_PINMUX_H
|
||||
#define CPU_SAMSUNG_EXYNOS5420_PINMUX_H
|
||||
|
||||
#include "periph.h"
|
||||
|
||||
enum {
|
||||
PINMUX_FLAG_NONE = 0x00000000,
|
||||
|
||||
/* Flags for eMMC */
|
||||
PINMUX_FLAG_8BIT_MODE = 1 << 0, /* SDMMC 8-bit mode */
|
||||
|
||||
/*
|
||||
* Flags for SPI.
|
||||
*/
|
||||
PINMUX_FLAG_SLAVE_MODE = 1 << 0, /* Slave mode */
|
||||
|
||||
/* Flags for SROM controller */
|
||||
PINMUX_FLAG_BANK = 3 << 0, /* bank number (0-3) */
|
||||
PINMUX_FLAG_16BIT = 1 << 2, /* 16-bit width */
|
||||
};
|
||||
|
||||
/**
|
||||
* Configures the pinmux for a particular peripheral.
|
||||
*
|
||||
* Each gpio can be configured in many different ways (4 bits on exynos)
|
||||
* such as "input", "output", "special function", "external interrupt"
|
||||
* etc. This function will configure the peripheral pinmux along with
|
||||
* pull-up/down and drive strength.
|
||||
*
|
||||
* @param peripheral peripheral to be configured
|
||||
* @param flags configure flags
|
||||
* @return 0 if ok, -1 on error (e.g. unsupported peripheral)
|
||||
*/
|
||||
int exynos_pinmux_config(enum periph_id peripheral, int flags);
|
||||
|
||||
#endif
|
|
@ -0,0 +1,138 @@
|
|||
/*
|
||||
* This file is part of the coreboot project.
|
||||
*
|
||||
* Copyright (C) 2012 Samsung Electronics
|
||||
*
|
||||
* 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; version 2 of 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
/* Power setup code for EXYNOS5 */
|
||||
|
||||
#include <console/console.h>
|
||||
#include <arch/io.h>
|
||||
#include <arch/hlt.h>
|
||||
#include "cpu.h"
|
||||
#include "power.h"
|
||||
#include "sysreg.h"
|
||||
|
||||
static void ps_hold_setup(void)
|
||||
{
|
||||
struct exynos5_power *power =
|
||||
samsung_get_base_power();
|
||||
|
||||
/* Set PS-Hold high */
|
||||
setbits_le32(&power->ps_hold_ctrl, POWER_PS_HOLD_CONTROL_DATA_HIGH);
|
||||
}
|
||||
|
||||
void power_reset(void)
|
||||
{
|
||||
struct exynos5_power *power =
|
||||
samsung_get_base_power();
|
||||
|
||||
/* Clear inform1 so there's no change we think we've got a wake reset */
|
||||
power->inform1 = 0;
|
||||
|
||||
setbits_le32(&power->sw_reset, 1);
|
||||
}
|
||||
|
||||
/* This function never returns */
|
||||
void power_shutdown(void)
|
||||
{
|
||||
struct exynos5_power *power =
|
||||
samsung_get_base_power();
|
||||
|
||||
clrbits_le32(&power->ps_hold_ctrl, POWER_PS_HOLD_CONTROL_DATA_HIGH);
|
||||
|
||||
hlt();
|
||||
}
|
||||
|
||||
void power_enable_dp_phy(void)
|
||||
{
|
||||
struct exynos5_power *power =
|
||||
samsung_get_base_power();
|
||||
|
||||
setbits_le32(&power->dptx_phy_control, DPTX_PHY_ENABLE);
|
||||
}
|
||||
|
||||
void power_enable_usb_phy(void)
|
||||
{
|
||||
struct exynos5_sysreg *sysreg =
|
||||
samsung_get_base_sysreg();
|
||||
struct exynos5_power *power =
|
||||
samsung_get_base_power();
|
||||
unsigned int phy_cfg;
|
||||
|
||||
/* Setting USB20PHY_CONFIG register to USB 2.0 HOST link */
|
||||
phy_cfg = readl(&sysreg->usb20_phy_cfg);
|
||||
if (phy_cfg & USB20_PHY_CFG_EN) {
|
||||
printk(BIOS_DEBUG, "USB 2.0 HOST link already selected\n");
|
||||
} else {
|
||||
phy_cfg |= USB20_PHY_CFG_EN;
|
||||
writel(phy_cfg, &sysreg->usb20_phy_cfg);
|
||||
}
|
||||
|
||||
/* Enabling USBHOST_PHY */
|
||||
setbits_le32(&power->usb_host_phy_ctrl, POWER_USB_HOST_PHY_CTRL_EN);
|
||||
}
|
||||
|
||||
void power_disable_usb_phy(void)
|
||||
{
|
||||
struct exynos5_power *power =
|
||||
samsung_get_base_power();
|
||||
|
||||
/* Disabling USBHost_PHY */
|
||||
clrbits_le32(&power->usb_host_phy_ctrl, POWER_USB_HOST_PHY_CTRL_EN);
|
||||
}
|
||||
|
||||
void power_enable_hw_thermal_trip(void)
|
||||
{
|
||||
struct exynos5_power *power =
|
||||
samsung_get_base_power();
|
||||
|
||||
/* Enable HW thermal trip */
|
||||
setbits_le32(&power->ps_hold_ctrl, POWER_ENABLE_HW_TRIP);
|
||||
}
|
||||
|
||||
uint32_t power_read_reset_status(void)
|
||||
{
|
||||
struct exynos5_power *power =
|
||||
samsung_get_base_power();
|
||||
|
||||
return power->inform1;
|
||||
}
|
||||
|
||||
void power_exit_wakeup(void)
|
||||
{
|
||||
struct exynos5_power *power =
|
||||
samsung_get_base_power();
|
||||
typedef void (*resume_func)(void);
|
||||
|
||||
((resume_func)power->inform0)();
|
||||
}
|
||||
|
||||
int power_init(void)
|
||||
{
|
||||
ps_hold_setup();
|
||||
return 0;
|
||||
}
|
||||
|
||||
void power_enable_xclkout(void)
|
||||
{
|
||||
struct exynos5_power *power =
|
||||
samsung_get_base_power();
|
||||
|
||||
/* use xxti for xclk out */
|
||||
clrsetbits_le32(&power->pmu_debug, PMU_DEBUG_CLKOUT_SEL_MASK,
|
||||
PMU_DEBUG_XXTI);
|
||||
}
|
|
@ -0,0 +1,90 @@
|
|||
/*
|
||||
* This file is part of the coreboot project.
|
||||
*
|
||||
* Copyright (C) 2012 Samsung Electronics
|
||||
*
|
||||
* 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; version 2 of 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
/* Register map for Exynos5 PMU */
|
||||
|
||||
#ifndef CPU_SAMSUNG_EXYNOS5420_POWER_H
|
||||
#define CPU_SAMSUNG_EXYNOS5420_POWER_H
|
||||
|
||||
/* Enable HW thermal trip with PS_HOLD_CONTROL register ENABLE_HW_TRIP bit */
|
||||
void power_enable_hw_thermal_trip(void);
|
||||
|
||||
#define MIPI_PHY1_CONTROL_ENABLE (1 << 0)
|
||||
#define MIPI_PHY1_CONTROL_M_RESETN (1 << 2)
|
||||
|
||||
#define POWER_USB_HOST_PHY_CTRL_EN (1 << 0)
|
||||
#define POWER_PS_HOLD_CONTROL_DATA_HIGH (1 << 8)
|
||||
#define POWER_ENABLE_HW_TRIP (1UL << 31)
|
||||
|
||||
#define DPTX_PHY_ENABLE (1 << 0)
|
||||
|
||||
/* PMU_DEBUG bits [12:8] = 0x1000 selects XXTI clock source */
|
||||
#define PMU_DEBUG_XXTI 0x1000
|
||||
/* Mask bit[12:8] for xxti clock selection */
|
||||
#define PMU_DEBUG_CLKOUT_SEL_MASK 0x1f00
|
||||
|
||||
/* Power Management Unit register map */
|
||||
struct exynos5_power {
|
||||
/* Add registers as and when required */
|
||||
uint8_t reserved1[0x0400];
|
||||
uint32_t sw_reset; /* 0x0400 */
|
||||
uint8_t reserved2[0x0304];
|
||||
uint32_t usb_host_phy_ctrl; /* 0x0708 */
|
||||
uint8_t reserved3[0x8];
|
||||
uint32_t mipi_phy1_control; /* 0x0714 */
|
||||
uint8_t reserved4[0x8];
|
||||
uint32_t dptx_phy_control; /* 0x0720 */
|
||||
uint8_t reserved5[0xdc];
|
||||
uint32_t inform0; /* 0x0800 */
|
||||
uint32_t inform1; /* 0x0804 */
|
||||
uint8_t reserved6[0x1f8];
|
||||
uint32_t pmu_debug; /* 0x0A00*/
|
||||
uint8_t reserved7[0x2908];
|
||||
uint32_t ps_hold_ctrl; /* 0x330c */
|
||||
} __attribute__ ((__packed__));
|
||||
|
||||
/**
|
||||
* Perform a software reset.
|
||||
*/
|
||||
void power_reset(void);
|
||||
|
||||
/**
|
||||
* Power off the system; it should never return.
|
||||
*/
|
||||
void power_shutdown(void);
|
||||
|
||||
/* Enable DPTX PHY */
|
||||
void power_enable_dp_phy(void);
|
||||
|
||||
void power_enable_usb_phy(void);
|
||||
void power_disable_usb_phy(void);
|
||||
|
||||
/* Initialize the pmic voltages to power up the system */
|
||||
int power_init(void);
|
||||
|
||||
/* Read the reset status. */
|
||||
uint32_t power_read_reset_status(void);
|
||||
|
||||
/* Read the resume function and call it. */
|
||||
void power_exit_wakeup(void);
|
||||
|
||||
/* pmu debug is used for xclkout, enable xclkout with source as XXTI */
|
||||
void power_enable_xclkout(void);
|
||||
|
||||
#endif
|
|
@ -0,0 +1,191 @@
|
|||
/*
|
||||
* This file is part of the coreboot project.
|
||||
*
|
||||
* Copyright (C) 2011 Samsung Electronics
|
||||
*
|
||||
* 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; version 2 of 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include <arch/io.h>
|
||||
#include "clk.h"
|
||||
#include "cpu.h"
|
||||
#include "periph.h"
|
||||
#include "pwm.h"
|
||||
|
||||
int pwm_enable(int pwm_id)
|
||||
{
|
||||
const struct s5p_timer *pwm =
|
||||
samsung_get_base_timer();
|
||||
unsigned long tcon;
|
||||
|
||||
tcon = readl(&pwm->tcon);
|
||||
tcon |= TCON_START(pwm_id);
|
||||
|
||||
writel(tcon, &pwm->tcon);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int pwm_check_enabled(int pwm_id)
|
||||
{
|
||||
const struct s5p_timer *pwm =
|
||||
samsung_get_base_timer();
|
||||
const unsigned long tcon = readl(&pwm->tcon);
|
||||
|
||||
return tcon & TCON_START(pwm_id);
|
||||
}
|
||||
|
||||
void pwm_disable(int pwm_id)
|
||||
{
|
||||
const struct s5p_timer *pwm =
|
||||
samsung_get_base_timer();
|
||||
unsigned long tcon;
|
||||
|
||||
tcon = readl(&pwm->tcon);
|
||||
tcon &= ~TCON_START(pwm_id);
|
||||
|
||||
writel(tcon, &pwm->tcon);
|
||||
}
|
||||
|
||||
static unsigned long pwm_calc_tin(int pwm_id, unsigned long freq)
|
||||
{
|
||||
unsigned long tin_parent_rate;
|
||||
unsigned int div;
|
||||
|
||||
tin_parent_rate = clock_get_periph_rate(PERIPH_ID_PWM0);
|
||||
|
||||
for (div = 2; div <= 16; div *= 2) {
|
||||
if ((tin_parent_rate / (div << 16)) < freq)
|
||||
return tin_parent_rate / div;
|
||||
}
|
||||
|
||||
return tin_parent_rate / 16;
|
||||
}
|
||||
|
||||
#define NS_IN_SEC 1000000000UL
|
||||
|
||||
int pwm_config(int pwm_id, int duty_ns, int period_ns)
|
||||
{
|
||||
const struct s5p_timer *pwm =
|
||||
samsung_get_base_timer();
|
||||
unsigned int offset;
|
||||
unsigned long tin_rate;
|
||||
unsigned long tin_ns;
|
||||
unsigned long frequency;
|
||||
unsigned long tcon;
|
||||
unsigned long tcnt;
|
||||
unsigned long tcmp;
|
||||
|
||||
/*
|
||||
* We currently avoid using 64bit arithmetic by using the
|
||||
* fact that anything faster than 1GHz is easily representable
|
||||
* by 32bits.
|
||||
*/
|
||||
if (period_ns > NS_IN_SEC || duty_ns > NS_IN_SEC || period_ns == 0)
|
||||
return -1;
|
||||
|
||||
if (duty_ns > period_ns)
|
||||
return -1;
|
||||
|
||||
frequency = NS_IN_SEC / period_ns;
|
||||
|
||||
/* Check to see if we are changing the clock rate of the PWM */
|
||||
tin_rate = pwm_calc_tin(pwm_id, frequency);
|
||||
|
||||
tin_ns = NS_IN_SEC / tin_rate;
|
||||
tcnt = period_ns / tin_ns;
|
||||
|
||||
/* Note, counters count down */
|
||||
tcmp = duty_ns / tin_ns;
|
||||
tcmp = tcnt - tcmp;
|
||||
|
||||
/* Update the PWM register block. */
|
||||
offset = pwm_id * 3;
|
||||
if (pwm_id < 4) {
|
||||
writel(tcnt, &pwm->tcntb0 + offset);
|
||||
writel(tcmp, &pwm->tcmpb0 + offset);
|
||||
}
|
||||
|
||||
tcon = readl(&pwm->tcon);
|
||||
tcon |= TCON_UPDATE(pwm_id);
|
||||
if (pwm_id < 4)
|
||||
tcon |= TCON_AUTO_RELOAD(pwm_id);
|
||||
else
|
||||
tcon |= TCON4_AUTO_RELOAD;
|
||||
writel(tcon, &pwm->tcon);
|
||||
|
||||
tcon &= ~TCON_UPDATE(pwm_id);
|
||||
writel(tcon, &pwm->tcon);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int pwm_init(int pwm_id, int div, int invert)
|
||||
{
|
||||
u32 val;
|
||||
const struct s5p_timer *pwm =
|
||||
samsung_get_base_timer();
|
||||
unsigned long ticks_per_period;
|
||||
unsigned int offset, prescaler;
|
||||
|
||||
/*
|
||||
* Timer Freq(HZ) =
|
||||
* PWM_CLK / { (prescaler_value + 1) * (divider_value) }
|
||||
*/
|
||||
|
||||
val = readl(&pwm->tcfg0);
|
||||
if (pwm_id < 2) {
|
||||
prescaler = PRESCALER_0;
|
||||
val &= ~0xff;
|
||||
val |= (prescaler & 0xff);
|
||||
} else {
|
||||
prescaler = PRESCALER_1;
|
||||
val &= ~(0xff << 8);
|
||||
val |= (prescaler & 0xff) << 8;
|
||||
}
|
||||
writel(val, &pwm->tcfg0);
|
||||
val = readl(&pwm->tcfg1);
|
||||
val &= ~(0xf << MUX_DIV_SHIFT(pwm_id));
|
||||
val |= (div & 0xf) << MUX_DIV_SHIFT(pwm_id);
|
||||
writel(val, &pwm->tcfg1);
|
||||
|
||||
|
||||
if (pwm_id == 4) {
|
||||
/*
|
||||
* TODO(sjg): Use this as a countdown timer for now. We count
|
||||
* down from the maximum value to 0, then reset.
|
||||
*/
|
||||
ticks_per_period = -1UL;
|
||||
} else {
|
||||
const unsigned long pwm_hz = 1000;
|
||||
unsigned long timer_rate_hz = clock_get_periph_rate(
|
||||
PERIPH_ID_PWM0) / ((prescaler + 1) * (1 << div));
|
||||
|
||||
ticks_per_period = timer_rate_hz / pwm_hz;
|
||||
}
|
||||
|
||||
/* set count value */
|
||||
offset = pwm_id * 3;
|
||||
|
||||
writel(ticks_per_period, &pwm->tcntb0 + offset);
|
||||
|
||||
val = readl(&pwm->tcon) & ~(0xf << TCON_OFFSET(pwm_id));
|
||||
if (invert && (pwm_id < 4))
|
||||
val |= TCON_INVERTER(pwm_id);
|
||||
writel(val, &pwm->tcon);
|
||||
|
||||
pwm_enable(pwm_id);
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,70 @@
|
|||
/*
|
||||
* This file is part of the coreboot project.
|
||||
*
|
||||
* Copyright (C) 2009 Samsung Electronics
|
||||
*
|
||||
* 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; version 2 of 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#ifndef CPU_SAMSUNG_EXYNOS5420_PWM_H
|
||||
#define CPU_SAMSUNG_EXYNOS5420_PWM_H
|
||||
|
||||
#define PRESCALER_0 (8 - 1) /* prescaler of timer 0, 1 */
|
||||
#define PRESCALER_1 (16 - 1) /* prescaler of timer 2, 3, 4 */
|
||||
|
||||
/* Divider MUX */
|
||||
#define MUX_DIV_1 0 /* 1/1 period */
|
||||
#define MUX_DIV_2 1 /* 1/2 period */
|
||||
#define MUX_DIV_4 2 /* 1/4 period */
|
||||
#define MUX_DIV_8 3 /* 1/8 period */
|
||||
#define MUX_DIV_16 4 /* 1/16 period */
|
||||
|
||||
#define MUX_DIV_SHIFT(x) (x * 4)
|
||||
|
||||
#define TCON_OFFSET(x) ((x + 1) * (!!x) << 2)
|
||||
|
||||
#define TCON_START(x) (1 << TCON_OFFSET(x))
|
||||
#define TCON_UPDATE(x) (1 << (TCON_OFFSET(x) + 1))
|
||||
#define TCON_INVERTER(x) (1 << (TCON_OFFSET(x) + 2))
|
||||
#define TCON_AUTO_RELOAD(x) (1 << (TCON_OFFSET(x) + 3))
|
||||
#define TCON4_AUTO_RELOAD (1 << 22)
|
||||
|
||||
struct s5p_timer {
|
||||
unsigned int tcfg0;
|
||||
unsigned int tcfg1;
|
||||
unsigned int tcon;
|
||||
unsigned int tcntb0;
|
||||
unsigned int tcmpb0;
|
||||
unsigned int tcnto0;
|
||||
unsigned int tcntb1;
|
||||
unsigned int tcmpb1;
|
||||
unsigned int tcnto1;
|
||||
unsigned int tcntb2;
|
||||
unsigned int tcmpb2;
|
||||
unsigned int tcnto2;
|
||||
unsigned int tcntb3;
|
||||
unsigned int tcmpb3;
|
||||
unsigned int tcnto3;
|
||||
unsigned int tcntb4;
|
||||
unsigned int tcnto4;
|
||||
unsigned int tintcstat;
|
||||
};
|
||||
|
||||
int pwm_config(int pwm_id, int duty_ns, int period_ns);
|
||||
int pwm_check_enabled(int pwm_id);
|
||||
void pwm_disable(int pwm_id);
|
||||
int pwm_enable(int pwm_id);
|
||||
int pwm_init(int pwm_id, int div, int invert);
|
||||
|
||||
#endif
|
|
@ -0,0 +1,26 @@
|
|||
/*
|
||||
* This file is part of the coreboot project.
|
||||
*
|
||||
* Copyright 2013 Google Inc.
|
||||
*
|
||||
* 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; version 2 of 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include <reset.h>
|
||||
#include <arch/io.h>
|
||||
|
||||
void soft_reset(void)
|
||||
{
|
||||
writel(0x1, samsung_get_base_swreset());
|
||||
}
|
|
@ -0,0 +1,753 @@
|
|||
/*
|
||||
* This file is part of the coreboot project.
|
||||
*
|
||||
* Copyright (C) 2012 Samsung Electronics
|
||||
*
|
||||
* 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; version 2 of 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
/* Machine Specific Values for SMDK5420 board based on Exynos5 */
|
||||
|
||||
#ifndef CPU_SAMSUNG_EXYNOS5420_SETUP_H
|
||||
#define CPU_SAMSUNG_EXYNOS5420_SETUP_H
|
||||
|
||||
struct exynos5_dmc;
|
||||
enum ddr_mode;
|
||||
struct exynos5_phy_control;
|
||||
|
||||
/* TZPC : Register Offsets */
|
||||
#define TZPC0_BASE 0x10100000
|
||||
#define TZPC1_BASE 0x10110000
|
||||
#define TZPC2_BASE 0x10120000
|
||||
#define TZPC3_BASE 0x10130000
|
||||
#define TZPC4_BASE 0x10140000
|
||||
#define TZPC5_BASE 0x10150000
|
||||
#define TZPC6_BASE 0x10160000
|
||||
#define TZPC7_BASE 0x10170000
|
||||
#define TZPC8_BASE 0x10180000
|
||||
#define TZPC9_BASE 0x10190000
|
||||
|
||||
/* APLL_CON1 */
|
||||
#define APLL_CON1_VAL (0x00203800)
|
||||
|
||||
/* MPLL_CON1 */
|
||||
#define MPLL_CON1_VAL (0x00203800)
|
||||
|
||||
/* CPLL_CON1 */
|
||||
#define CPLL_CON1_VAL (0x00203800)
|
||||
|
||||
/* GPLL_CON1 */
|
||||
#define GPLL_CON1_VAL (0x00203800)
|
||||
|
||||
/* EPLL_CON1, CON2 */
|
||||
#define EPLL_CON1_VAL 0x00000000
|
||||
#define EPLL_CON2_VAL 0x00000080
|
||||
|
||||
/* VPLL_CON1, CON2 */
|
||||
#define VPLL_CON1_VAL 0x00000000
|
||||
#define VPLL_CON2_VAL 0x00000080
|
||||
|
||||
/* BPLL_CON1 */
|
||||
#define BPLL_CON1_VAL 0x00203800
|
||||
|
||||
/* Set PLL */
|
||||
#define set_pll(mdiv, pdiv, sdiv) (1<<31 | mdiv<<16 | pdiv<<8 | sdiv)
|
||||
|
||||
/* CLK_SRC_CPU */
|
||||
/* 0 = MOUTAPLL, 1 = SCLKMPLL */
|
||||
#define MUX_HPM_SEL 0
|
||||
#define MUX_CPU_SEL 0
|
||||
#define MUX_APLL_SEL 1
|
||||
|
||||
#define CLK_SRC_CPU_VAL ((MUX_HPM_SEL << 20) \
|
||||
| (MUX_CPU_SEL << 16) \
|
||||
| (MUX_APLL_SEL))
|
||||
|
||||
/* MEMCONTROL register bit fields */
|
||||
#define DMC_MEMCONTROL_CLK_STOP_DISABLE (0 << 0)
|
||||
#define DMC_MEMCONTROL_DPWRDN_DISABLE (0 << 1)
|
||||
#define DMC_MEMCONTROL_DPWRDN_ACTIVE_PRECHARGE (0 << 2)
|
||||
#define DMC_MEMCONTROL_TP_DISABLE (0 << 4)
|
||||
#define DMC_MEMCONTROL_DSREF_DISABLE (0 << 5)
|
||||
#define DMC_MEMCONTROL_DSREF_ENABLE (1 << 5)
|
||||
#define DMC_MEMCONTROL_ADD_LAT_PALL_CYCLE(x) (x << 6)
|
||||
|
||||
#define DMC_MEMCONTROL_MEM_TYPE_LPDDR3 (7 << 8)
|
||||
#define DMC_MEMCONTROL_MEM_TYPE_DDR3 (6 << 8)
|
||||
#define DMC_MEMCONTROL_MEM_TYPE_LPDDR2 (5 << 8)
|
||||
|
||||
#define DMC_MEMCONTROL_MEM_WIDTH_32BIT (2 << 12)
|
||||
|
||||
#define DMC_MEMCONTROL_NUM_CHIP_1 (0 << 16)
|
||||
#define DMC_MEMCONTROL_NUM_CHIP_2 (1 << 16)
|
||||
|
||||
#define DMC_MEMCONTROL_BL_8 (3 << 20)
|
||||
#define DMC_MEMCONTROL_BL_4 (2 << 20)
|
||||
|
||||
#define DMC_MEMCONTROL_PZQ_DISABLE (0 << 24)
|
||||
|
||||
#define DMC_MEMCONTROL_MRR_BYTE_7_0 (0 << 25)
|
||||
#define DMC_MEMCONTROL_MRR_BYTE_15_8 (1 << 25)
|
||||
#define DMC_MEMCONTROL_MRR_BYTE_23_16 (2 << 25)
|
||||
#define DMC_MEMCONTROL_MRR_BYTE_31_24 (3 << 25)
|
||||
|
||||
/* MEMCONFIG0 register bit fields */
|
||||
#define DMC_MEMCONFIGx_CHIP_MAP_INTERLEAVED (1 << 12)
|
||||
#define DMC_MEMCONFIGx_CHIP_COL_10 (3 << 8)
|
||||
#define DMC_MEMCONFIGx_CHIP_ROW_14 (2 << 4)
|
||||
#define DMC_MEMCONFIGx_CHIP_ROW_15 (3 << 4)
|
||||
#define DMC_MEMCONFIGx_CHIP_BANK_8 (3 << 0)
|
||||
|
||||
#define DMC_MEMBASECONFIGx_CHIP_BASE(x) (x << 16)
|
||||
#define DMC_MEMBASECONFIGx_CHIP_MASK(x) (x << 0)
|
||||
#define DMC_MEMBASECONFIG_VAL(x) ( \
|
||||
DMC_MEMBASECONFIGx_CHIP_BASE(x) | \
|
||||
DMC_MEMBASECONFIGx_CHIP_MASK(0x780) \
|
||||
)
|
||||
|
||||
#define DMC_MEMBASECONFIG0_VAL DMC_MEMBASECONFIG_VAL(0x40)
|
||||
#define DMC_MEMBASECONFIG1_VAL DMC_MEMBASECONFIG_VAL(0x80)
|
||||
|
||||
#define DMC_PRECHCONFIG_VAL 0xFF000000
|
||||
#define DMC_PWRDNCONFIG_VAL 0xFFFF00FF
|
||||
|
||||
#define DMC_CONCONTROL_RESET_VAL 0x0FFF0000
|
||||
#define DFI_INIT_START (1 << 28)
|
||||
#define EMPTY (1 << 8)
|
||||
#define AREF_EN (1 << 5)
|
||||
|
||||
#define DFI_INIT_COMPLETE_CHO (1 << 2)
|
||||
#define DFI_INIT_COMPLETE_CH1 (1 << 3)
|
||||
|
||||
#define RDLVL_COMPLETE_CHO (1 << 14)
|
||||
#define RDLVL_COMPLETE_CH1 (1 << 15)
|
||||
|
||||
#define CLK_STOP_EN (1 << 0)
|
||||
#define DPWRDN_EN (1 << 1)
|
||||
#define DSREF_EN (1 << 5)
|
||||
|
||||
/* COJCONTROL register bit fields */
|
||||
#define DMC_CONCONTROL_IO_PD_CON_DISABLE (0 << 3)
|
||||
#define DMC_CONCONTROL_AREF_EN_DISABLE (0 << 5)
|
||||
#define DMC_CONCONTROL_EMPTY_DISABLE (0 << 8)
|
||||
#define DMC_CONCONTROL_EMPTY_ENABLE (1 << 8)
|
||||
#define DMC_CONCONTROL_RD_FETCH_DISABLE (0x0 << 12)
|
||||
#define DMC_CONCONTROL_TIMEOUT_LEVEL0 (0xFFF << 16)
|
||||
#define DMC_CONCONTROL_DFI_INIT_START_DISABLE (0 << 28)
|
||||
|
||||
/* CLK_DIV_CPU0_VAL */
|
||||
#define CLK_DIV_CPU0_VAL ((ARM2_RATIO << 28) \
|
||||
| (APLL_RATIO << 24) \
|
||||
| (PCLK_DBG_RATIO << 20) \
|
||||
| (ATB_RATIO << 16) \
|
||||
| (PERIPH_RATIO << 12) \
|
||||
| (ACP_RATIO << 8) \
|
||||
| (CPUD_RATIO << 4) \
|
||||
| (ARM_RATIO))
|
||||
|
||||
|
||||
/* CLK_FSYS */
|
||||
#define CLK_SRC_FSYS0_VAL 0x66666
|
||||
#define CLK_DIV_FSYS0_VAL 0x0BB00000
|
||||
|
||||
/* CLK_DIV_CPU1 */
|
||||
#define HPM_RATIO 0x2
|
||||
#define COPY_RATIO 0x0
|
||||
|
||||
/* CLK_DIV_CPU1 = 0x00000003 */
|
||||
#define CLK_DIV_CPU1_VAL ((HPM_RATIO << 4) \
|
||||
| (COPY_RATIO))
|
||||
|
||||
/* CLK_SRC_CORE0 */
|
||||
#define CLK_SRC_CORE0_VAL 0x00000000
|
||||
|
||||
/* CLK_SRC_CORE1 */
|
||||
#define CLK_SRC_CORE1_VAL 0x100
|
||||
|
||||
/* CLK_DIV_CORE0 */
|
||||
#define CLK_DIV_CORE0_VAL 0x00120000
|
||||
|
||||
/* CLK_DIV_CORE1 */
|
||||
#define CLK_DIV_CORE1_VAL 0x07070700
|
||||
|
||||
/* CLK_DIV_SYSRGT */
|
||||
#define CLK_DIV_SYSRGT_VAL 0x00000111
|
||||
|
||||
/* CLK_DIV_ACP */
|
||||
#define CLK_DIV_ACP_VAL 0x12
|
||||
|
||||
/* CLK_DIV_SYSLFT */
|
||||
#define CLK_DIV_SYSLFT_VAL 0x00000311
|
||||
|
||||
/* CLK_SRC_CDREX */
|
||||
#define CLK_SRC_CDREX_VAL 0x1
|
||||
|
||||
/* CLK_DIV_CDREX */
|
||||
#define MCLK_CDREX2_RATIO 0x0
|
||||
#define ACLK_EFCON_RATIO 0x1
|
||||
#define MCLK_DPHY_RATIO 0x1
|
||||
#define MCLK_CDREX_RATIO 0x1
|
||||
#define ACLK_C2C_200_RATIO 0x1
|
||||
#define C2C_CLK_400_RATIO 0x1
|
||||
#define PCLK_CDREX_RATIO 0x1
|
||||
#define ACLK_CDREX_RATIO 0x1
|
||||
|
||||
#define CLK_DIV_CDREX_VAL ((MCLK_DPHY_RATIO << 24) \
|
||||
| (C2C_CLK_400_RATIO << 6) \
|
||||
| (PCLK_CDREX_RATIO << 4) \
|
||||
| (ACLK_CDREX_RATIO))
|
||||
|
||||
/* CLK_SRC_TOP0 */
|
||||
#define MUX_ACLK_300_GSCL_SEL 0x0
|
||||
#define MUX_ACLK_300_GSCL_MID_SEL 0x0
|
||||
#define MUX_ACLK_400_G3D_MID_SEL 0x0
|
||||
#define MUX_ACLK_333_SEL 0x0
|
||||
#define MUX_ACLK_300_DISP1_SEL 0x0
|
||||
#define MUX_ACLK_300_DISP1_MID_SEL 0x0
|
||||
#define MUX_ACLK_200_SEL 0x0
|
||||
#define MUX_ACLK_166_SEL 0x0
|
||||
#define CLK_SRC_TOP0_VAL ((MUX_ACLK_300_GSCL_SEL << 25) \
|
||||
| (MUX_ACLK_300_GSCL_MID_SEL << 24) \
|
||||
| (MUX_ACLK_400_G3D_MID_SEL << 20) \
|
||||
| (MUX_ACLK_333_SEL << 16) \
|
||||
| (MUX_ACLK_300_DISP1_SEL << 15) \
|
||||
| (MUX_ACLK_300_DISP1_MID_SEL << 14) \
|
||||
| (MUX_ACLK_200_SEL << 12) \
|
||||
| (MUX_ACLK_166_SEL << 8))
|
||||
|
||||
/* CLK_SRC_TOP1 */
|
||||
#define MUX_ACLK_400_G3D_SEL 0x1
|
||||
#define MUX_ACLK_400_ISP_SEL 0x0
|
||||
#define MUX_ACLK_400_IOP_SEL 0x0
|
||||
#define MUX_ACLK_MIPI_HSI_TXBASE_SEL 0x0
|
||||
#define MUX_ACLK_300_GSCL_MID1_SEL 0x0
|
||||
#define MUX_ACLK_300_DISP1_MID1_SEL 0x0
|
||||
#define CLK_SRC_TOP1_VAL ((MUX_ACLK_400_G3D_SEL << 28) \
|
||||
|(MUX_ACLK_400_ISP_SEL << 24) \
|
||||
|(MUX_ACLK_400_IOP_SEL << 20) \
|
||||
|(MUX_ACLK_MIPI_HSI_TXBASE_SEL << 16) \
|
||||
|(MUX_ACLK_300_GSCL_MID1_SEL << 12) \
|
||||
|(MUX_ACLK_300_DISP1_MID1_SEL << 8))
|
||||
|
||||
/* CLK_SRC_TOP2 */
|
||||
#define MUX_GPLL_SEL 0x1
|
||||
#define MUX_BPLL_USER_SEL 0x0
|
||||
#define MUX_MPLL_USER_SEL 0x0
|
||||
#define MUX_VPLL_SEL 0x1
|
||||
#define MUX_EPLL_SEL 0x1
|
||||
#define MUX_CPLL_SEL 0x1
|
||||
#define VPLLSRC_SEL 0x0
|
||||
#define CLK_SRC_TOP2_VAL ((MUX_GPLL_SEL << 28) \
|
||||
| (MUX_BPLL_USER_SEL << 24) \
|
||||
| (MUX_MPLL_USER_SEL << 20) \
|
||||
| (MUX_VPLL_SEL << 16) \
|
||||
| (MUX_EPLL_SEL << 12) \
|
||||
| (MUX_CPLL_SEL << 8) \
|
||||
| (VPLLSRC_SEL))
|
||||
/* CLK_SRC_TOP3 */
|
||||
#define MUX_ACLK_333_SUB_SEL 0x1
|
||||
#define MUX_ACLK_400_SUB_SEL 0x1
|
||||
#define MUX_ACLK_266_ISP_SUB_SEL 0x1
|
||||
#define MUX_ACLK_266_GPS_SUB_SEL 0x0
|
||||
#define MUX_ACLK_300_GSCL_SUB_SEL 0x1
|
||||
#define MUX_ACLK_266_GSCL_SUB_SEL 0x1
|
||||
#define MUX_ACLK_300_DISP1_SUB_SEL 0x1
|
||||
#define MUX_ACLK_200_DISP1_SUB_SEL 0x1
|
||||
#define CLK_SRC_TOP3_VAL ((MUX_ACLK_333_SUB_SEL << 24) \
|
||||
| (MUX_ACLK_400_SUB_SEL << 20) \
|
||||
| (MUX_ACLK_266_ISP_SUB_SEL << 16) \
|
||||
| (MUX_ACLK_266_GPS_SUB_SEL << 12) \
|
||||
| (MUX_ACLK_300_GSCL_SUB_SEL << 10) \
|
||||
| (MUX_ACLK_266_GSCL_SUB_SEL << 8) \
|
||||
| (MUX_ACLK_300_DISP1_SUB_SEL << 6) \
|
||||
| (MUX_ACLK_200_DISP1_SUB_SEL << 4))
|
||||
|
||||
/* CLK_DIV_TOP0 */
|
||||
#define ACLK_300_DISP1_RATIO 0x2
|
||||
#define ACLK_400_G3D_RATIO 0x0
|
||||
#define ACLK_333_RATIO 0x0
|
||||
#define ACLK_266_RATIO 0x2
|
||||
#define ACLK_200_RATIO 0x3
|
||||
#define ACLK_166_RATIO 0x1
|
||||
#define ACLK_133_RATIO 0x1
|
||||
#define ACLK_66_RATIO 0x5
|
||||
|
||||
#define CLK_DIV_TOP0_VAL ((ACLK_300_DISP1_RATIO << 28) \
|
||||
| (ACLK_400_G3D_RATIO << 24) \
|
||||
| (ACLK_333_RATIO << 20) \
|
||||
| (ACLK_266_RATIO << 16) \
|
||||
| (ACLK_200_RATIO << 12) \
|
||||
| (ACLK_166_RATIO << 8) \
|
||||
| (ACLK_133_RATIO << 4) \
|
||||
| (ACLK_66_RATIO))
|
||||
|
||||
/* CLK_DIV_TOP1 */
|
||||
#define ACLK_MIPI_HSI_TX_BASE_RATIO 0x3
|
||||
#define ACLK_66_PRE_RATIO 0x1
|
||||
#define ACLK_400_ISP_RATIO 0x1
|
||||
#define ACLK_400_IOP_RATIO 0x1
|
||||
#define ACLK_300_GSCL_RATIO 0x2
|
||||
|
||||
#define CLK_DIV_TOP1_VAL ((ACLK_MIPI_HSI_TX_BASE_RATIO << 28) \
|
||||
| (ACLK_66_PRE_RATIO << 24) \
|
||||
| (ACLK_400_ISP_RATIO << 20) \
|
||||
| (ACLK_400_IOP_RATIO << 16) \
|
||||
| (ACLK_300_GSCL_RATIO << 12))
|
||||
|
||||
/* APLL_LOCK */
|
||||
#define APLL_LOCK_VAL (0x546)
|
||||
/* MPLL_LOCK */
|
||||
#define MPLL_LOCK_VAL (0x546)
|
||||
/* CPLL_LOCK */
|
||||
#define CPLL_LOCK_VAL (0x546)
|
||||
/* GPLL_LOCK */
|
||||
#define GPLL_LOCK_VAL (0x546)
|
||||
/* EPLL_LOCK */
|
||||
#define EPLL_LOCK_VAL (0x3A98)
|
||||
/* VPLL_LOCK */
|
||||
#define VPLL_LOCK_VAL (0x3A98)
|
||||
/* BPLL_LOCK */
|
||||
#define BPLL_LOCK_VAL (0x546)
|
||||
|
||||
#define MUX_MCLK_CDREX_SEL (1 << 4)
|
||||
#define MUX_MCLK_DPHY_SEL (1 << 8)
|
||||
|
||||
#define MUX_APLL_SEL_MASK (1 << 0)
|
||||
#define MUX_MPLL_FOUT_SEL (1 << 4)
|
||||
#define MUX_BPLL_FOUT_SEL (1 << 0)
|
||||
#define MUX_MPLL_SEL_MASK (1 << 8)
|
||||
#define MPLL_SEL_MOUT_MPLLFOUT (2 << 8)
|
||||
#define MUX_CPLL_SEL_MASK (1 << 8)
|
||||
#define MUX_EPLL_SEL_MASK (1 << 12)
|
||||
#define MUX_VPLL_SEL_MASK (1 << 16)
|
||||
#define MUX_GPLL_SEL_MASK (1 << 28)
|
||||
#define MUX_BPLL_SEL_MASK (1 << 0)
|
||||
#define MUX_HPM_SEL_MASK (1 << 20)
|
||||
#define HPM_SEL_SCLK_MPLL (1 << 21)
|
||||
#define APLL_CON0_LOCKED (1 << 29)
|
||||
#define MPLL_CON0_LOCKED (1 << 29)
|
||||
#define BPLL_CON0_LOCKED (1 << 29)
|
||||
#define CPLL_CON0_LOCKED (1 << 29)
|
||||
#define EPLL_CON0_LOCKED (1 << 29)
|
||||
#define GPLL_CON0_LOCKED (1 << 29)
|
||||
#define VPLL_CON0_LOCKED (1 << 29)
|
||||
#define CLK_REG_DISABLE 0x0
|
||||
#define TOP2_VAL 0x0110000
|
||||
|
||||
/* CLK_SRC_PERIC0 */
|
||||
#define PWM_SEL 6
|
||||
#define UART3_SEL 6
|
||||
#define UART2_SEL 6
|
||||
#define UART1_SEL 6
|
||||
#define UART0_SEL 6
|
||||
/* SRC_CLOCK = SCLK_MPLL */
|
||||
#define CLK_SRC_PERIC0_VAL ((PWM_SEL << 24) \
|
||||
| (UART3_SEL << 12) \
|
||||
| (UART2_SEL << 8) \
|
||||
| (UART1_SEL << 4) \
|
||||
| (UART0_SEL))
|
||||
|
||||
/* CLK_SRC_PERIC1 */
|
||||
/* SRC_CLOCK = SCLK_MPLL */
|
||||
#define SPI0_SEL 6
|
||||
#define SPI1_SEL 6
|
||||
#define SPI2_SEL 6
|
||||
#define CLK_SRC_PERIC1_VAL ((SPI2_SEL << 24) \
|
||||
| (SPI1_SEL << 20) \
|
||||
| (SPI0_SEL << 16))
|
||||
|
||||
/* SCLK_SRC_ISP - set SPI0/1 to 6 = SCLK_MPLL_USER */
|
||||
#define SPI0_ISP_SEL 6
|
||||
#define SPI1_ISP_SEL 6
|
||||
#define SCLK_SRC_ISP_VAL (SPI1_ISP_SEL << 4) \
|
||||
| (SPI0_ISP_SEL << 0)
|
||||
|
||||
/* SCLK_DIV_ISP - set SPI0/1 to 0xf = divide by 16 */
|
||||
#define SPI0_ISP_RATIO 0xf
|
||||
#define SPI1_ISP_RATIO 0xf
|
||||
#define SCLK_DIV_ISP_VAL (SPI1_ISP_RATIO << 12) \
|
||||
| (SPI0_ISP_RATIO << 0)
|
||||
|
||||
/* CLK_DIV_PERIL0 */
|
||||
#define UART5_RATIO 7
|
||||
#define UART4_RATIO 7
|
||||
#define UART3_RATIO 7
|
||||
#define UART2_RATIO 7
|
||||
#define UART1_RATIO 7
|
||||
#define UART0_RATIO 7
|
||||
|
||||
#define CLK_DIV_PERIC0_VAL ((UART3_RATIO << 12) \
|
||||
| (UART2_RATIO << 8) \
|
||||
| (UART1_RATIO << 4) \
|
||||
| (UART0_RATIO))
|
||||
/* CLK_DIV_PERIC1 */
|
||||
#define SPI1_RATIO 0x7
|
||||
#define SPI0_RATIO 0xf
|
||||
#define SPI1_SUB_RATIO 0x0
|
||||
#define SPI0_SUB_RATIO 0x0
|
||||
#define CLK_DIV_PERIC1_VAL ((SPI1_SUB_RATIO << 24) \
|
||||
| ((SPI1_RATIO << 16) \
|
||||
| (SPI0_SUB_RATIO << 8) \
|
||||
| (SPI0_RATIO << 0)))
|
||||
|
||||
/* CLK_DIV_PERIC2 */
|
||||
#define SPI2_RATIO 0xf
|
||||
#define SPI2_SUB_RATIO 0x0
|
||||
#define CLK_DIV_PERIC2_VAL ((SPI2_SUB_RATIO << 8) \
|
||||
| (SPI2_RATIO << 0))
|
||||
/* CLK_DIV_FSYS2 */
|
||||
#define MMC2_RATIO_MASK 0xf
|
||||
#define MMC2_RATIO_VAL 0x3
|
||||
#define MMC2_RATIO_OFFSET 0
|
||||
|
||||
#define MMC2_PRE_RATIO_MASK 0xff
|
||||
#define MMC2_PRE_RATIO_VAL 0x9
|
||||
#define MMC2_PRE_RATIO_OFFSET 8
|
||||
|
||||
#define MMC3_RATIO_MASK 0xf
|
||||
#define MMC3_RATIO_VAL 0x1
|
||||
#define MMC3_RATIO_OFFSET 16
|
||||
|
||||
#define MMC3_PRE_RATIO_MASK 0xff
|
||||
#define MMC3_PRE_RATIO_VAL 0x0
|
||||
#define MMC3_PRE_RATIO_OFFSET 24
|
||||
|
||||
/* CLK_SRC_LEX */
|
||||
#define CLK_SRC_LEX_VAL 0x0
|
||||
|
||||
/* CLK_DIV_LEX */
|
||||
#define CLK_DIV_LEX_VAL 0x10
|
||||
|
||||
/* CLK_DIV_R0X */
|
||||
#define CLK_DIV_R0X_VAL 0x10
|
||||
|
||||
/* CLK_DIV_L0X */
|
||||
#define CLK_DIV_R1X_VAL 0x10
|
||||
|
||||
/* CLK_DIV_ISP0 */
|
||||
#define CLK_DIV_ISP0_VAL 0x31
|
||||
|
||||
/* CLK_DIV_ISP1 */
|
||||
#define CLK_DIV_ISP1_VAL 0x0
|
||||
|
||||
/* CLK_DIV_ISP2 */
|
||||
#define CLK_DIV_ISP2_VAL 0x1
|
||||
|
||||
/* CLK_SRC_DISP1_0 */
|
||||
#define CLK_SRC_DISP1_0_VAL 0x6
|
||||
|
||||
/*
|
||||
* DIV_DISP1_0
|
||||
* For DP, divisor should be 2
|
||||
*/
|
||||
#define CLK_DIV_DISP1_0_FIMD1 (2 << 0)
|
||||
|
||||
/* CLK_GATE_IP_DISP1 */
|
||||
#define CLK_GATE_DP1_ALLOW (1 << 4)
|
||||
|
||||
/* CLK_GATE_IP_SYSRGT */
|
||||
#define CLK_C2C_MASK (1 << 1)
|
||||
|
||||
/* CLK_GATE_IP_ACP */
|
||||
#define CLK_SMMUG2D_MASK (1 << 7)
|
||||
#define CLK_SMMUSSS_MASK (1 << 6)
|
||||
#define CLK_SMMUMDMA_MASK (1 << 5)
|
||||
#define CLK_ID_REMAPPER_MASK (1 << 4)
|
||||
#define CLK_G2D_MASK (1 << 3)
|
||||
#define CLK_SSS_MASK (1 << 2)
|
||||
#define CLK_MDMA_MASK (1 << 1)
|
||||
#define CLK_SECJTAG_MASK (1 << 0)
|
||||
|
||||
/* CLK_GATE_BUS_SYSLFT */
|
||||
#define CLK_EFCLK_MASK (1 << 16)
|
||||
|
||||
/* CLK_GATE_IP_ISP0 */
|
||||
#define CLK_UART_ISP_MASK (1 << 31)
|
||||
#define CLK_WDT_ISP_MASK (1 << 30)
|
||||
#define CLK_PWM_ISP_MASK (1 << 28)
|
||||
#define CLK_MTCADC_ISP_MASK (1 << 27)
|
||||
#define CLK_I2C1_ISP_MASK (1 << 26)
|
||||
#define CLK_I2C0_ISP_MASK (1 << 25)
|
||||
#define CLK_MPWM_ISP_MASK (1 << 24)
|
||||
#define CLK_MCUCTL_ISP_MASK (1 << 23)
|
||||
#define CLK_INT_COMB_ISP_MASK (1 << 22)
|
||||
#define CLK_SMMU_MCUISP_MASK (1 << 13)
|
||||
#define CLK_SMMU_SCALERP_MASK (1 << 12)
|
||||
#define CLK_SMMU_SCALERC_MASK (1 << 11)
|
||||
#define CLK_SMMU_FD_MASK (1 << 10)
|
||||
#define CLK_SMMU_DRC_MASK (1 << 9)
|
||||
#define CLK_SMMU_ISP_MASK (1 << 8)
|
||||
#define CLK_GICISP_MASK (1 << 7)
|
||||
#define CLK_ARM9S_MASK (1 << 6)
|
||||
#define CLK_MCUISP_MASK (1 << 5)
|
||||
#define CLK_SCALERP_MASK (1 << 4)
|
||||
#define CLK_SCALERC_MASK (1 << 3)
|
||||
#define CLK_FD_MASK (1 << 2)
|
||||
#define CLK_DRC_MASK (1 << 1)
|
||||
#define CLK_ISP_MASK (1 << 0)
|
||||
|
||||
/* CLK_GATE_IP_ISP1 */
|
||||
#define CLK_SPI1_ISP_MASK (1 << 13)
|
||||
#define CLK_SPI0_ISP_MASK (1 << 12)
|
||||
#define CLK_SMMU3DNR_MASK (1 << 7)
|
||||
#define CLK_SMMUDIS1_MASK (1 << 6)
|
||||
#define CLK_SMMUDIS0_MASK (1 << 5)
|
||||
#define CLK_SMMUODC_MASK (1 << 4)
|
||||
#define CLK_3DNR_MASK (1 << 2)
|
||||
#define CLK_DIS_MASK (1 << 1)
|
||||
#define CLK_ODC_MASK (1 << 0)
|
||||
|
||||
/* CLK_GATE_IP_GSCL */
|
||||
#define CLK_SMMUFIMC_LITE2_MASK (1 << 20)
|
||||
#define CLK_SMMUFIMC_LITE1_MASK (1 << 12)
|
||||
#define CLK_SMMUFIMC_LITE0_MASK (1 << 11)
|
||||
#define CLK_SMMUGSCL3_MASK (1 << 10)
|
||||
#define CLK_SMMUGSCL2_MASK (1 << 9)
|
||||
#define CLK_SMMUGSCL1_MASK (1 << 8)
|
||||
#define CLK_SMMUGSCL0_MASK (1 << 7)
|
||||
#define CLK_GSCL_WRAP_B_MASK (1 << 6)
|
||||
#define CLK_GSCL_WRAP_A_MASK (1 << 5)
|
||||
#define CLK_CAMIF_TOP_MASK (1 << 4)
|
||||
#define CLK_GSCL3_MASK (1 << 3)
|
||||
#define CLK_GSCL2_MASK (1 << 2)
|
||||
#define CLK_GSCL1_MASK (1 << 1)
|
||||
#define CLK_GSCL0_MASK (1 << 0)
|
||||
|
||||
/* CLK_GATE_IP_MFC */
|
||||
#define CLK_SMMUMFCR_MASK (1 << 2)
|
||||
#define CLK_SMMUMFCL_MASK (1 << 1)
|
||||
#define CLK_MFC_MASK (1 << 0)
|
||||
|
||||
#define SCLK_MPWM_ISP_MASK (1 << 0)
|
||||
|
||||
/* CLK_GATE_IP_DISP1 */
|
||||
#define CLK_SMMUTVX_MASK (1 << 9)
|
||||
#define CLK_ASYNCTVX_MASK (1 << 7)
|
||||
#define CLK_HDMI_MASK (1 << 6)
|
||||
#define CLK_MIXER_MASK (1 << 5)
|
||||
#define CLK_DSIM1_MASK (1 << 3)
|
||||
|
||||
/* CLK_GATE_IP_GEN */
|
||||
#define CLK_SMMUMDMA1_MASK (1 << 9)
|
||||
#define CLK_SMMUJPEG_MASK (1 << 7)
|
||||
#define CLK_SMMUROTATOR_MASK (1 << 6)
|
||||
#define CLK_MDMA1_MASK (1 << 4)
|
||||
#define CLK_JPEG_MASK (1 << 2)
|
||||
#define CLK_ROTATOR_MASK (1 << 1)
|
||||
|
||||
/* CLK_GATE_IP_FSYS */
|
||||
#define CLK_WDT_IOP_MASK (1 << 30)
|
||||
#define CLK_SMMUMCU_IOP_MASK (1 << 26)
|
||||
#define CLK_SATA_PHY_I2C_MASK (1 << 25)
|
||||
#define CLK_SATA_PHY_CTRL_MASK (1 << 24)
|
||||
#define CLK_MCUCTL_MASK (1 << 23)
|
||||
#define CLK_NFCON_MASK (1 << 22)
|
||||
#define CLK_SMMURTIC_MASK (1 << 11)
|
||||
#define CLK_RTIC_MASK (1 << 9)
|
||||
#define CLK_MIPI_HSI_MASK (1 << 8)
|
||||
#define CLK_USBOTG_MASK (1 << 7)
|
||||
#define CLK_SATA_MASK (1 << 6)
|
||||
#define CLK_PDMA1_MASK (1 << 2)
|
||||
#define CLK_PDMA0_MASK (1 << 1)
|
||||
#define CLK_MCU_IOP_MASK (1 << 0)
|
||||
|
||||
/* CLK_GATE_IP_PERIC */
|
||||
#define CLK_HS_I2C3_MASK (1 << 31)
|
||||
#define CLK_HS_I2C2_MASK (1 << 30)
|
||||
#define CLK_HS_I2C1_MASK (1 << 29)
|
||||
#define CLK_HS_I2C0_MASK (1 << 28)
|
||||
#define CLK_AC97_MASK (1 << 27)
|
||||
#define CLK_SPDIF_MASK (1 << 26)
|
||||
#define CLK_PCM2_MASK (1 << 23)
|
||||
#define CLK_PCM1_MASK (1 << 22)
|
||||
#define CLK_I2S2_MASK (1 << 21)
|
||||
#define CLK_I2S1_MASK (1 << 20)
|
||||
#define CLK_SPI2_MASK (1 << 18)
|
||||
#define CLK_SPI0_MASK (1 << 16)
|
||||
#define CLK_I2CHDMI_MASK (1 << 14)
|
||||
#define CLK_I2C7_MASK (1 << 13)
|
||||
#define CLK_I2C6_MASK (1 << 12)
|
||||
#define CLK_I2C5_MASK (1 << 11)
|
||||
#define CLK_I2C4_MASK (1 << 10)
|
||||
#define CLK_I2C3_MASK (1 << 9)
|
||||
#define CLK_I2C2_MASK (1 << 8)
|
||||
#define CLK_I2C1_MASK (1 << 7)
|
||||
#define CLK_I2C0_MASK (1 << 6)
|
||||
|
||||
/* CLK_GATE_IP_PERIS */
|
||||
#define CLK_RTC_MASK (1 << 20)
|
||||
#define CLK_TZPC9_MASK (1 << 15)
|
||||
#define CLK_TZPC8_MASK (1 << 14)
|
||||
#define CLK_TZPC7_MASK (1 << 13)
|
||||
#define CLK_TZPC6_MASK (1 << 12)
|
||||
#define CLK_TZPC5_MASK (1 << 11)
|
||||
#define CLK_TZPC4_MASK (1 << 10)
|
||||
#define CLK_TZPC3_MASK (1 << 9)
|
||||
#define CLK_TZPC2_MASK (1 << 8)
|
||||
#define CLK_TZPC1_MASK (1 << 7)
|
||||
#define CLK_TZPC0_MASK (1 << 6)
|
||||
#define CLK_CHIPID_MASK (1 << 0)
|
||||
|
||||
/* CLK_GATE_BLOCK */
|
||||
#define CLK_ACP_MASK (1 << 7)
|
||||
|
||||
/* CLK_GATE_IP_CDREX */
|
||||
#define CLK_TZASC_DRBXW_MASK (1 << 23)
|
||||
#define CLK_TZASC_DRBXR_MASK (1 << 22)
|
||||
#define CLK_TZASC_XLBXW_MASK (1 << 21)
|
||||
#define CLK_TZASC_XLBXR_MASK (1 << 20)
|
||||
#define CLK_TZASC_XR1BXW_MASK (1 << 19)
|
||||
#define CLK_TZASC_XR1BXR_MASK (1 << 18)
|
||||
#define CLK_DPHY1_MASK (1 << 5)
|
||||
#define CLK_DPHY0_MASK (1 << 4)
|
||||
|
||||
/*
|
||||
* TZPC Register Value :
|
||||
* R0SIZE: 0x0 : Size of secured ram
|
||||
*/
|
||||
#define R0SIZE 0x0
|
||||
|
||||
/*
|
||||
* TZPC Decode Protection Register Value :
|
||||
* DECPROTXSET: 0xFF : Set Decode region to non-secure
|
||||
*/
|
||||
#define DECPROTXSET 0xFF
|
||||
|
||||
#define LPDDR3PHY_CTRL_PHY_RESET (1 << 0)
|
||||
#define LPDDR3PHY_CTRL_PHY_RESET_OFF (0 << 0)
|
||||
|
||||
#define PHY_CON0_RESET_VAL 0x17020a40
|
||||
#define P0_CMD_EN (1 << 14)
|
||||
#define BYTE_RDLVL_EN (1 << 13)
|
||||
#define CTRL_SHGATE (1 << 8)
|
||||
|
||||
#define PHY_CON1_RESET_VAL 0x09210100
|
||||
#define CTRL_GATEDURADJ_MASK (0xf << 20)
|
||||
|
||||
#define PHY_CON2_RESET_VAL 0x00010004
|
||||
#define INIT_DESKEW_EN (1 << 6)
|
||||
#define RDLVL_GATE_EN (1 << 24)
|
||||
|
||||
/*ZQ Configurations */
|
||||
#define PHY_CON16_RESET_VAL 0x08000304
|
||||
|
||||
#define ZQ_CLK_DIV_EN (1 << 18)
|
||||
#define ZQ_MANUAL_STR (1 << 1)
|
||||
#define ZQ_DONE (1 << 0)
|
||||
|
||||
#define CTRL_RDLVL_GATE_ENABLE 1
|
||||
#define CTRL_RDLVL_GATE_DISABLE 1
|
||||
|
||||
/* Direct Command */
|
||||
#define DIRECT_CMD_NOP 0x07000000
|
||||
#define DIRECT_CMD_PALL 0x01000000
|
||||
#define DIRECT_CMD_ZQINIT 0x0a000000
|
||||
#define DIRECT_CMD_CHANNEL_SHIFT 28
|
||||
#define DIRECT_CMD_CHIP_SHIFT 20
|
||||
|
||||
/* DMC PHY Control0 register */
|
||||
#define PHY_CONTROL0_RESET_VAL 0x0
|
||||
#define MEM_TERM_EN (1 << 31) /* Termination enable for memory */
|
||||
#define PHY_TERM_EN (1 << 30) /* Termination enable for PHY */
|
||||
#define DMC_CTRL_SHGATE (1 << 29) /* Duration of DQS gating signal */
|
||||
#define FP_RSYNC (1 << 3) /* Force DLL resyncronization */
|
||||
|
||||
/* Driver strength for CK, CKE, CS & CA */
|
||||
#define IMP_OUTPUT_DRV_40_OHM 0x5
|
||||
#define IMP_OUTPUT_DRV_30_OHM 0x7
|
||||
#define CA_CK_DRVR_DS_OFFSET 9
|
||||
#define CA_CKE_DRVR_DS_OFFSET 6
|
||||
#define CA_CS_DRVR_DS_OFFSET 3
|
||||
#define CA_ADR_DRVR_DS_OFFSET 0
|
||||
|
||||
#define PHY_CON42_CTRL_BSTLEN_SHIFT 8
|
||||
#define PHY_CON42_CTRL_RDLAT_SHIFT 0
|
||||
|
||||
struct mem_timings;
|
||||
|
||||
/* Errors that we can encourter in low-level setup */
|
||||
enum {
|
||||
SETUP_ERR_OK,
|
||||
SETUP_ERR_RDLV_COMPLETE_TIMEOUT = -1,
|
||||
SETUP_ERR_ZQ_CALIBRATION_FAILURE = -2,
|
||||
};
|
||||
|
||||
/* Functions common between LPDDR2 and DDR3 */
|
||||
|
||||
/* CPU info initialization code */
|
||||
void cpu_info_init(void);
|
||||
|
||||
void mem_ctrl_init(void);
|
||||
/*
|
||||
* Memory variant specific initialization code
|
||||
*
|
||||
* @param mem Memory timings for this memory type.
|
||||
* @param mem_iv_size Memory interleaving size is a configurable parameter
|
||||
* which the DMC uses to decide how to split a memory
|
||||
* chunk into smaller chunks to support concurrent
|
||||
* accesses; may vary across boards.
|
||||
* @param mem_reset Reset memory during initialization.
|
||||
* @return 0 if ok, SETUP_ERR_... if there is a problem
|
||||
*/
|
||||
int ddr3_mem_ctrl_init(struct mem_timings *mem, unsigned long mem_iv_size,
|
||||
int mem_reset);
|
||||
|
||||
/*
|
||||
* Configure ZQ I/O interface
|
||||
*
|
||||
* @param mem Memory timings for this memory type.
|
||||
* @param phy0_ctrl Pointer to struct containing PHY0 control reg
|
||||
* @param phy1_ctrl Pointer to struct containing PHY1 control reg
|
||||
* @return 0 if ok, -1 on error
|
||||
*/
|
||||
int dmc_config_zq(struct mem_timings *mem,
|
||||
struct exynos5_phy_control *phy0_ctrl,
|
||||
struct exynos5_phy_control *phy1_ctrl);
|
||||
|
||||
/*
|
||||
* Send NOP and MRS/EMRS Direct commands
|
||||
*
|
||||
* @param mem Memory timings for this memory type.
|
||||
* @param dmc Pointer to struct of DMC registers
|
||||
*/
|
||||
void dmc_config_mrs(struct mem_timings *mem, struct exynos5_dmc *dmc);
|
||||
|
||||
/*
|
||||
* Send PALL Direct commands
|
||||
*
|
||||
* @param mem Memory timings for this memory type.
|
||||
* @param dmc Pointer to struct of DMC registers
|
||||
*/
|
||||
void dmc_config_prech(struct mem_timings *mem, struct exynos5_dmc *dmc);
|
||||
|
||||
/*
|
||||
* Configure the memconfig and membaseconfig registers
|
||||
*
|
||||
* @param mem Memory timings for this memory type.
|
||||
* @param exynos5_dmc Pointer to struct of DMC registers
|
||||
*/
|
||||
void dmc_config_memory(struct mem_timings *mem, struct exynos5_dmc *dmc);
|
||||
|
||||
/* Set the PS-Hold drive value */
|
||||
void ps_hold_setup(void);
|
||||
/*
|
||||
* Reset the DLL. This function is common between DDR3 and LPDDR2.
|
||||
* However, the reset value is different. So we are passing a flag
|
||||
* ddr_mode to distinguish between LPDDR2 and DDR3.
|
||||
*
|
||||
* @param exynos5_dmc Pointer to struct of DMC registers
|
||||
* @param ddr_mode Type of DDR memory
|
||||
*/
|
||||
void update_reset_dll(struct exynos5_dmc *, enum ddr_mode);
|
||||
#endif
|
|
@ -0,0 +1,222 @@
|
|||
/*
|
||||
* This file is part of the coreboot project.
|
||||
*
|
||||
* Copyright (C) 2011 Samsung Electronics
|
||||
* Copyright 2013 Google Inc.
|
||||
*
|
||||
* 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; version 2 of 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include <console/console.h>
|
||||
#include <arch/io.h>
|
||||
#include <stdlib.h>
|
||||
#include <assert.h>
|
||||
#include "gpio.h"
|
||||
#include "clk.h"
|
||||
#include "spi.h"
|
||||
|
||||
#define OM_STAT (0x1f << 1)
|
||||
#define EXYNOS_BASE_SPI1 ((void *)0x12d30000)
|
||||
|
||||
#if defined(CONFIG_DEBUG_SPI) && CONFIG_DEBUG_SPI
|
||||
# define DEBUG_SPI(x,...) printk(BIOS_DEBUG, "EXYNOS_SPI: " x)
|
||||
#else
|
||||
# define DEBUG_SPI(x,...)
|
||||
#endif
|
||||
|
||||
static void exynos_spi_rx_tx(struct exynos_spi *regs, int todo,
|
||||
void *dinp, void const *doutp, int i)
|
||||
{
|
||||
int rx_lvl, tx_lvl;
|
||||
unsigned int *rxp = (unsigned int *)(dinp + (i * (32 * 1024)));
|
||||
unsigned int out_bytes, in_bytes;
|
||||
|
||||
// TODO In currrent implementation, every read/write must be aligned to
|
||||
// 4 bytes, otherwise you may get timeout or other unexpected results.
|
||||
ASSERT(todo % 4 == 0);
|
||||
|
||||
out_bytes = in_bytes = todo;
|
||||
setbits_le32(®s->ch_cfg, SPI_CH_RST);
|
||||
clrbits_le32(®s->ch_cfg, SPI_CH_RST);
|
||||
writel(((todo * 8) / 32) | SPI_PACKET_CNT_EN, ®s->pkt_cnt);
|
||||
|
||||
while (in_bytes) {
|
||||
uint32_t spi_sts;
|
||||
int temp;
|
||||
|
||||
spi_sts = readl(®s->spi_sts);
|
||||
rx_lvl = ((spi_sts >> 15) & 0x7f);
|
||||
tx_lvl = ((spi_sts >> 6) & 0x7f);
|
||||
while (tx_lvl < 32 && out_bytes) {
|
||||
// TODO The "writing" (tx) is not supported now; that's
|
||||
// why we write garbage to keep driving FIFO clock.
|
||||
temp = 0xffffffff;
|
||||
writel(temp, ®s->tx_data);
|
||||
out_bytes -= 4;
|
||||
tx_lvl += 4;
|
||||
}
|
||||
while (rx_lvl >= 4 && in_bytes) {
|
||||
temp = readl(®s->rx_data);
|
||||
if (rxp)
|
||||
*rxp++ = temp;
|
||||
in_bytes -= 4;
|
||||
rx_lvl -= 4;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* set up SPI channel */
|
||||
int exynos_spi_open(struct exynos_spi *regs)
|
||||
{
|
||||
/* set the spi1 GPIO */
|
||||
|
||||
/* set pktcnt and enable it */
|
||||
writel(4 | SPI_PACKET_CNT_EN, ®s->pkt_cnt);
|
||||
/* set FB_CLK_SEL */
|
||||
writel(SPI_FB_DELAY_180, ®s->fb_clk);
|
||||
/* set CH_WIDTH and BUS_WIDTH as word */
|
||||
setbits_le32(®s->mode_cfg,
|
||||
SPI_MODE_CH_WIDTH_WORD | SPI_MODE_BUS_WIDTH_WORD);
|
||||
clrbits_le32(®s->ch_cfg, SPI_CH_CPOL_L); /* CPOL: active high */
|
||||
|
||||
/* clear rx and tx channel if set priveously */
|
||||
clrbits_le32(®s->ch_cfg, SPI_RX_CH_ON | SPI_TX_CH_ON);
|
||||
|
||||
setbits_le32(®s->swap_cfg,
|
||||
SPI_RX_SWAP_EN | SPI_RX_BYTE_SWAP | SPI_RX_HWORD_SWAP);
|
||||
|
||||
/* do a soft reset */
|
||||
setbits_le32(®s->ch_cfg, SPI_CH_RST);
|
||||
clrbits_le32(®s->ch_cfg, SPI_CH_RST);
|
||||
|
||||
/* now set rx and tx channel ON */
|
||||
setbits_le32(®s->ch_cfg, SPI_RX_CH_ON | SPI_TX_CH_ON | SPI_CH_HS_EN);
|
||||
clrbits_le32(®s->cs_reg, SPI_SLAVE_SIG_INACT); /* CS low */
|
||||
return 0;
|
||||
}
|
||||
|
||||
int exynos_spi_read(struct exynos_spi *regs, void *dest, u32 len, u32 off)
|
||||
{
|
||||
int upto, todo;
|
||||
int i;
|
||||
/* Send read instruction (0x3h) followed by a 24 bit addr */
|
||||
writel((SF_READ_DATA_CMD << 24) | off, ®s->tx_data);
|
||||
|
||||
/* waiting for TX done */
|
||||
while (!(readl(®s->spi_sts) & SPI_ST_TX_DONE));
|
||||
|
||||
for (upto = 0, i = 0; upto < len; upto += todo, i++) {
|
||||
todo = MIN(len - upto, (1 << 15));
|
||||
exynos_spi_rx_tx(regs, todo, dest, (void *)(off), i);
|
||||
}
|
||||
|
||||
setbits_le32(®s->cs_reg, SPI_SLAVE_SIG_INACT);/* make the CS high */
|
||||
|
||||
/*
|
||||
* Let put controller mode to BYTE as
|
||||
* SPI driver does not support WORD mode yet
|
||||
*/
|
||||
clrbits_le32(®s->mode_cfg,
|
||||
SPI_MODE_CH_WIDTH_WORD | SPI_MODE_BUS_WIDTH_WORD);
|
||||
writel(0, ®s->swap_cfg);
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
int exynos_spi_close(struct exynos_spi *regs)
|
||||
{
|
||||
/*
|
||||
* Flush spi tx, rx fifos and reset the SPI controller
|
||||
* and clear rx/tx channel
|
||||
*/
|
||||
clrsetbits_le32(®s->ch_cfg, SPI_CH_HS_EN, SPI_CH_RST);
|
||||
clrbits_le32(®s->ch_cfg, SPI_CH_RST);
|
||||
clrbits_le32(®s->ch_cfg, SPI_TX_CH_ON | SPI_RX_CH_ON);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// SPI as CBFS media.
|
||||
struct exynos_spi_media {
|
||||
struct exynos_spi *regs;
|
||||
struct cbfs_simple_buffer buffer;
|
||||
};
|
||||
|
||||
static int exynos_spi_cbfs_open(struct cbfs_media *media) {
|
||||
struct exynos_spi_media *spi = (struct exynos_spi_media*)media->context;
|
||||
DEBUG_SPI("exynos_spi_cbfs_open\n");
|
||||
return exynos_spi_open(spi->regs);
|
||||
}
|
||||
|
||||
static int exynos_spi_cbfs_close(struct cbfs_media *media) {
|
||||
struct exynos_spi_media *spi = (struct exynos_spi_media*)media->context;
|
||||
DEBUG_SPI("exynos_spi_cbfs_close\n");
|
||||
return exynos_spi_close(spi->regs);
|
||||
}
|
||||
|
||||
static size_t exynos_spi_cbfs_read(struct cbfs_media *media, void *dest,
|
||||
size_t offset, size_t count) {
|
||||
struct exynos_spi_media *spi = (struct exynos_spi_media*)media->context;
|
||||
int bytes;
|
||||
DEBUG_SPI("exynos_spi_cbfs_read(%u)\n", count);
|
||||
bytes = exynos_spi_read(spi->regs, dest, count, offset);
|
||||
// Flush and re-open the device.
|
||||
exynos_spi_close(spi->regs);
|
||||
exynos_spi_open(spi->regs);
|
||||
return bytes;
|
||||
}
|
||||
|
||||
static void *exynos_spi_cbfs_map(struct cbfs_media *media, size_t offset,
|
||||
size_t count) {
|
||||
struct exynos_spi_media *spi = (struct exynos_spi_media*)media->context;
|
||||
DEBUG_SPI("exynos_spi_cbfs_map\n");
|
||||
// See exynos_spi_rx_tx for I/O alignment limitation.
|
||||
if (count % 4)
|
||||
count += 4 - (count % 4);
|
||||
return cbfs_simple_buffer_map(&spi->buffer, media, offset, count);
|
||||
}
|
||||
|
||||
static void *exynos_spi_cbfs_unmap(struct cbfs_media *media,
|
||||
const void *address) {
|
||||
struct exynos_spi_media *spi = (struct exynos_spi_media*)media->context;
|
||||
DEBUG_SPI("exynos_spi_cbfs_unmap\n");
|
||||
return cbfs_simple_buffer_unmap(&spi->buffer, address);
|
||||
}
|
||||
|
||||
int initialize_exynos_spi_cbfs_media(struct cbfs_media *media,
|
||||
void *buffer_address,
|
||||
size_t buffer_size) {
|
||||
// TODO Replace static variable to support multiple streams.
|
||||
static struct exynos_spi_media context;
|
||||
DEBUG_SPI("initialize_exynos_spi_cbfs_media\n");
|
||||
|
||||
context.regs = EXYNOS_BASE_SPI1;
|
||||
context.buffer.allocated = context.buffer.last_allocate = 0;
|
||||
context.buffer.buffer = buffer_address;
|
||||
context.buffer.size = buffer_size;
|
||||
media->context = (void*)&context;
|
||||
media->open = exynos_spi_cbfs_open;
|
||||
media->close = exynos_spi_cbfs_close;
|
||||
media->read = exynos_spi_cbfs_read;
|
||||
media->map = exynos_spi_cbfs_map;
|
||||
media->unmap = exynos_spi_cbfs_unmap;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int init_default_cbfs_media(struct cbfs_media *media) {
|
||||
return initialize_exynos_spi_cbfs_media(
|
||||
media,
|
||||
(void*)CONFIG_CBFS_CACHE_ADDRESS,
|
||||
CONFIG_CBFS_CACHE_SIZE);
|
||||
}
|
|
@ -0,0 +1,98 @@
|
|||
/*
|
||||
* This file is part of the coreboot project.
|
||||
*
|
||||
* Copyright (C) 2012 Samsung Electronics
|
||||
*
|
||||
* 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; version 2 of 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#ifndef CPU_SAMSUNG_EXYNOS5420_SPI_H
|
||||
#define CPU_SAMSUNG_EXYNOS5420_SPI_H
|
||||
|
||||
/* This driver serves as a CBFS media source. */
|
||||
#include <cbfs.h>
|
||||
|
||||
/* SPI peripheral register map; padded to 64KB */
|
||||
struct exynos_spi {
|
||||
unsigned int ch_cfg; /* 0x00 */
|
||||
unsigned char reserved0[4];
|
||||
unsigned int mode_cfg; /* 0x08 */
|
||||
unsigned int cs_reg; /* 0x0c */
|
||||
unsigned char reserved1[4];
|
||||
unsigned int spi_sts; /* 0x14 */
|
||||
unsigned int tx_data; /* 0x18 */
|
||||
unsigned int rx_data; /* 0x1c */
|
||||
unsigned int pkt_cnt; /* 0x20 */
|
||||
unsigned char reserved2[4];
|
||||
unsigned int swap_cfg; /* 0x28 */
|
||||
unsigned int fb_clk; /* 0x2c */
|
||||
unsigned char padding[0xffd0];
|
||||
};
|
||||
|
||||
#define EXYNOS_SPI_MAX_FREQ 50000000
|
||||
|
||||
#define SPI_TIMEOUT_MS 10
|
||||
|
||||
#define SF_READ_DATA_CMD 0x3
|
||||
|
||||
/* SPI_CHCFG */
|
||||
#define SPI_CH_HS_EN (1 << 6)
|
||||
#define SPI_CH_RST (1 << 5)
|
||||
#define SPI_SLAVE_MODE (1 << 4)
|
||||
#define SPI_CH_CPOL_L (1 << 3)
|
||||
#define SPI_CH_CPHA_B (1 << 2)
|
||||
#define SPI_RX_CH_ON (1 << 1)
|
||||
#define SPI_TX_CH_ON (1 << 0)
|
||||
|
||||
/* SPI_MODECFG */
|
||||
#define SPI_MODE_CH_WIDTH_WORD (0x2 << 29)
|
||||
#define SPI_MODE_BUS_WIDTH_WORD (0x2 << 17)
|
||||
|
||||
/* SPI_CSREG */
|
||||
#define SPI_SLAVE_SIG_INACT (1 << 0)
|
||||
|
||||
/* SPI_STS */
|
||||
#define SPI_ST_TX_DONE (1 << 25)
|
||||
#define SPI_FIFO_LVL_MASK 0x1ff
|
||||
#define SPI_TX_LVL_OFFSET 6
|
||||
#define SPI_RX_LVL_OFFSET 15
|
||||
|
||||
/* Feedback Delay */
|
||||
#define SPI_CLK_BYPASS (0 << 0)
|
||||
#define SPI_FB_DELAY_90 (1 << 0)
|
||||
#define SPI_FB_DELAY_180 (2 << 0)
|
||||
#define SPI_FB_DELAY_270 (3 << 0)
|
||||
|
||||
/* Packet Count */
|
||||
#define SPI_PACKET_CNT_EN (1 << 16)
|
||||
|
||||
/* Swap config */
|
||||
#define SPI_TX_SWAP_EN (1 << 0)
|
||||
#define SPI_TX_BYTE_SWAP (1 << 2)
|
||||
#define SPI_TX_HWORD_SWAP (1 << 3)
|
||||
#define SPI_TX_BYTE_SWAP (1 << 2)
|
||||
#define SPI_RX_SWAP_EN (1 << 4)
|
||||
#define SPI_RX_BYTE_SWAP (1 << 6)
|
||||
#define SPI_RX_HWORD_SWAP (1 << 7)
|
||||
|
||||
/* API */
|
||||
int exynos_spi_open(struct exynos_spi *regs);
|
||||
int exynos_spi_read(struct exynos_spi *regs, void *dest, u32 len, u32 off);
|
||||
int exynos_spi_close(struct exynos_spi *regs);
|
||||
|
||||
/* Serve as CBFS media source */
|
||||
int initialize_exynos_spi_cbfs_media(struct cbfs_media *media,
|
||||
void *buffer_address,
|
||||
size_t buffer_size);
|
||||
#endif
|
|
@ -0,0 +1,37 @@
|
|||
/*
|
||||
* This file is part of the coreboot project.
|
||||
*
|
||||
* Copyright (c) 2012 Samsung Electronics Co., Ltd.
|
||||
*
|
||||
* 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; version 2 of 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
/* Register map for Exynos5 sysreg */
|
||||
|
||||
#ifndef CPU_SAMSUNG_EXYNOS5420_SYSREG_H
|
||||
#define CPU_SAMSUNG_EXYNOS5420_SYSREG_H
|
||||
|
||||
/* sysreg map */
|
||||
struct exynos5_sysreg {
|
||||
/* Add registers as and when required */
|
||||
unsigned char res1[0x214];
|
||||
unsigned int disp1blk_cfg;
|
||||
unsigned char res2[0x18];
|
||||
unsigned int usb20_phy_cfg;
|
||||
};
|
||||
|
||||
#define FIMDBYPASS_DISP1 (1 << 15)
|
||||
#define USB20_PHY_CFG_EN (1 << 0)
|
||||
|
||||
#endif
|
|
@ -0,0 +1,110 @@
|
|||
/*
|
||||
* This file is part of the coreboot project.
|
||||
*
|
||||
* Copyright (C) 2009 Samsung Electronics
|
||||
*
|
||||
* 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; version 2 of 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include <console/console.h>
|
||||
#include <arch/io.h>
|
||||
#include <timer.h>
|
||||
#include <delay.h>
|
||||
#include "timer.h"
|
||||
#include "pwm.h"
|
||||
#include "clk.h"
|
||||
#include "cpu.h"
|
||||
|
||||
static unsigned long long timer_reset_value;
|
||||
static unsigned long lastinc;
|
||||
|
||||
/* macro to read the 16 bit timer */
|
||||
static inline struct s5p_timer *s5p_get_base_timer(void)
|
||||
{
|
||||
return samsung_get_base_timer();
|
||||
}
|
||||
|
||||
/**
|
||||
* Read the countdown timer.
|
||||
*
|
||||
* This operates at 1MHz and counts downwards. It will wrap about every
|
||||
* hour (2^32 microseconds).
|
||||
*
|
||||
* @return current value of timer
|
||||
*/
|
||||
static unsigned long timer_get_us_down(void)
|
||||
{
|
||||
struct s5p_timer *const timer = s5p_get_base_timer();
|
||||
|
||||
return readl(&timer->tcnto4);
|
||||
}
|
||||
|
||||
void init_timer(void)
|
||||
{
|
||||
/* Timer may have been enabled in SPL */
|
||||
if (!pwm_check_enabled(4)) {
|
||||
/* PWM Timer 4 */
|
||||
pwm_init(4, MUX_DIV_4, 0);
|
||||
pwm_config(4, 100000, 100000);
|
||||
pwm_enable(4);
|
||||
|
||||
/* Use this as the current monotonic time in us */
|
||||
timer_reset_value = 0;
|
||||
|
||||
/* Use this as the last timer value we saw */
|
||||
lastinc = timer_get_us_down();
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* timer without interrupts
|
||||
*/
|
||||
unsigned long get_timer(unsigned long base)
|
||||
{
|
||||
unsigned long now = timer_get_us_down();
|
||||
|
||||
/*
|
||||
* Increment the time by the amount elapsed since the last read.
|
||||
* The timer may have wrapped around, but it makes no difference to
|
||||
* our arithmetic here.
|
||||
*/
|
||||
timer_reset_value += lastinc - now;
|
||||
lastinc = now;
|
||||
|
||||
/* Divide by 1000 to convert from us to ms */
|
||||
return timer_reset_value / 1000 - base;
|
||||
}
|
||||
|
||||
/* delay x useconds */
|
||||
void udelay(unsigned usec)
|
||||
{
|
||||
struct mono_time current, end;
|
||||
|
||||
timer_monotonic_get(¤t);
|
||||
end = current;
|
||||
mono_time_add_usecs(&end, usec);
|
||||
|
||||
if (mono_time_after(¤t, &end)) {
|
||||
printk(BIOS_EMERG, "udelay: 0x%08x is impossibly large\n",
|
||||
usec);
|
||||
/* There's not much we can do if usec is too big. Use a long,
|
||||
* paranoid delay value and hope for the best... */
|
||||
end = current;
|
||||
mono_time_add_usecs(&end, USECS_PER_SEC);
|
||||
}
|
||||
|
||||
while (mono_time_before(¤t, &end))
|
||||
timer_monotonic_get(¤t);
|
||||
}
|
||||
|
|
@ -0,0 +1,25 @@
|
|||
/*
|
||||
* This file is part of the coreboot project.
|
||||
*
|
||||
* Copyright 2013 Google Inc.
|
||||
*
|
||||
* 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; version 2 of 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#ifndef CPU_SAMSUNG_EXYNOS5420_TIMER_H
|
||||
#define CPU_SAMSUNG_EXYNOS5420_TIMER_H
|
||||
|
||||
unsigned long get_timer(unsigned long base);
|
||||
|
||||
#endif
|
|
@ -0,0 +1,215 @@
|
|||
/*
|
||||
* This file is part of the coreboot project.
|
||||
*
|
||||
* Copyright (C) 2012 Samsung Electronics
|
||||
* Copyright 2013 Google Inc.
|
||||
*
|
||||
* 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; version 2 of 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
/* EXYNOS - Thermal Management Unit */
|
||||
|
||||
#include <console/console.h>
|
||||
#include <arch/io.h>
|
||||
#include "power.h"
|
||||
#include "tmu.h"
|
||||
|
||||
#define TRIMINFO_RELOAD 1
|
||||
#define CORE_EN 1
|
||||
#define THERM_TRIP_EN (1 << 12)
|
||||
|
||||
#define INTEN_RISE0 1
|
||||
#define INTEN_RISE1 (1 << 4)
|
||||
#define INTEN_RISE2 (1 << 8)
|
||||
#define INTEN_FALL0 (1 << 16)
|
||||
#define INTEN_FALL1 (1 << 20)
|
||||
#define INTEN_FALL2 (1 << 24)
|
||||
|
||||
#define TRIM_INFO_MASK 0xff
|
||||
|
||||
#define INTCLEAR_RISE0 1
|
||||
#define INTCLEAR_RISE1 (1 << 4)
|
||||
#define INTCLEAR_RISE2 (1 << 8)
|
||||
#define INTCLEAR_FALL0 (1 << 16)
|
||||
#define INTCLEAR_FALL1 (1 << 20)
|
||||
#define INTCLEAR_FALL2 (1 << 24)
|
||||
#define INTCLEARALL (INTCLEAR_RISE0 | INTCLEAR_RISE1 | \
|
||||
INTCLEAR_RISE2 | INTCLEAR_FALL0 | \
|
||||
INTCLEAR_FALL1 | INTCLEAR_FALL2)
|
||||
|
||||
struct tmu_info exynos5420_tmu_info = {
|
||||
.tmu_base = 0x10060000,
|
||||
.tmu_mux = 6,
|
||||
.data = {
|
||||
.ts = {
|
||||
.min_val = 25,
|
||||
.max_val = 125,
|
||||
.start_warning = 95,
|
||||
.start_tripping = 105,
|
||||
.hardware_tripping = 110,
|
||||
},
|
||||
.efuse_min_value = 40,
|
||||
.efuse_value = 55,
|
||||
.efuse_max_value = 100,
|
||||
.slope = 0x10008802,
|
||||
},
|
||||
.dc_value = 25,
|
||||
};
|
||||
|
||||
/*
|
||||
* After reading temperature code from register, compensating
|
||||
* its value and calculating celsius temperatue,
|
||||
* get current temperatue.
|
||||
*
|
||||
* @return current temperature of the chip as sensed by TMU
|
||||
*/
|
||||
static int get_cur_temp(struct tmu_info *info)
|
||||
{
|
||||
int cur_temp;
|
||||
struct tmu_reg *reg = (struct tmu_reg *)info->tmu_base;
|
||||
|
||||
/* Temperature code range between min 25 and max 125 */
|
||||
cur_temp = readl(®->current_temp) & 0xff;
|
||||
|
||||
/* Calibrate current temperature */
|
||||
if (cur_temp)
|
||||
cur_temp = cur_temp - info->te1 + info->dc_value;
|
||||
|
||||
return cur_temp;
|
||||
}
|
||||
|
||||
/*
|
||||
* Monitors status of the TMU device and exynos temperature
|
||||
*
|
||||
* @info TMU info
|
||||
* @temp pointer to the current temperature value
|
||||
* @return enum tmu_status_t value, code indicating event to execute
|
||||
*/
|
||||
enum tmu_status_t tmu_monitor(struct tmu_info *info, int *temp)
|
||||
{
|
||||
if (info->tmu_state == TMU_STATUS_INIT)
|
||||
return -1;
|
||||
|
||||
int cur_temp;
|
||||
struct tmu_data *data = &info->data;
|
||||
|
||||
/* Read current temperature of the SOC */
|
||||
cur_temp = get_cur_temp(info);
|
||||
*temp = cur_temp;
|
||||
|
||||
/* Temperature code lies between min 25 and max 125 */
|
||||
if (cur_temp >= data->ts.start_tripping &&
|
||||
cur_temp <= data->ts.max_val)
|
||||
return TMU_STATUS_TRIPPED;
|
||||
else if (cur_temp >= data->ts.start_warning)
|
||||
return TMU_STATUS_WARNING;
|
||||
else if (cur_temp < data->ts.start_warning &&
|
||||
cur_temp >= data->ts.min_val)
|
||||
return TMU_STATUS_NORMAL;
|
||||
/* Temperature code does not lie between min 25 and max 125 */
|
||||
else {
|
||||
info->tmu_state = TMU_STATUS_INIT;
|
||||
printk(BIOS_DEBUG, "EXYNOS_TMU: Thermal reading failed\n");
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Calibrate and calculate threshold values and
|
||||
* enable interrupt levels
|
||||
*
|
||||
* @param info pointer to the tmu_info struct
|
||||
*/
|
||||
static void tmu_setup_parameters(struct tmu_info *info)
|
||||
{
|
||||
unsigned int te_temp, con;
|
||||
unsigned int warning_code, trip_code, hwtrip_code;
|
||||
unsigned int cooling_temp;
|
||||
unsigned int rising_value;
|
||||
struct tmu_data *data = &info->data;
|
||||
struct tmu_reg *reg = (struct tmu_reg *)info->tmu_base;
|
||||
|
||||
/* Must reload for using efuse value at EXYNOS */
|
||||
writel(TRIMINFO_RELOAD, ®->triminfo_control);
|
||||
|
||||
/* Get the compensation parameter */
|
||||
te_temp = readl(®->triminfo);
|
||||
info->te1 = te_temp & TRIM_INFO_MASK;
|
||||
info->te2 = ((te_temp >> 8) & TRIM_INFO_MASK);
|
||||
|
||||
if ((data->efuse_min_value > info->te1) ||
|
||||
(info->te1 > data->efuse_max_value)
|
||||
|| (info->te2 != 0))
|
||||
info->te1 = data->efuse_value;
|
||||
|
||||
/* Get RISING & FALLING Threshold value */
|
||||
warning_code = data->ts.start_warning
|
||||
+ info->te1 - info->dc_value;
|
||||
trip_code = data->ts.start_tripping
|
||||
+ info->te1 - info->dc_value;
|
||||
hwtrip_code = data->ts.hardware_tripping
|
||||
+ info->te1 - info->dc_value;
|
||||
|
||||
cooling_temp = 0;
|
||||
|
||||
rising_value = ((warning_code << 8) |
|
||||
(trip_code << 16) |
|
||||
(hwtrip_code << 24));
|
||||
|
||||
/* Set interrupt level */
|
||||
writel(rising_value, ®->threshold_temp_rise);
|
||||
writel(cooling_temp, ®->threshold_temp_fall);
|
||||
|
||||
/*
|
||||
* Need to init all register settings after getting parameter info
|
||||
* [28:23] vref [11:8] slope - Tuning parameter
|
||||
*
|
||||
* WARNING: this slope value writes into many bits in the tmu_control
|
||||
* register, with the default FDT value of 268470274 (0x10008802)
|
||||
* we are using this essentially sets the default register setting
|
||||
* from the TRM for tmu_control.
|
||||
* TODO(bhthompson): rewrite this code such that we are not performing
|
||||
* a hard wipe of tmu_control and re verify functionality.
|
||||
*/
|
||||
writel(data->slope, ®->tmu_control);
|
||||
|
||||
writel(INTCLEARALL, ®->intclear);
|
||||
/* TMU core enable */
|
||||
con = readl(®->tmu_control);
|
||||
con |= (info->tmu_mux << 20) | THERM_TRIP_EN | CORE_EN;
|
||||
|
||||
writel(con, ®->tmu_control);
|
||||
|
||||
/* Enable HW thermal trip */
|
||||
power_enable_hw_thermal_trip();
|
||||
|
||||
/* LEV1 LEV2 interrupt enable */
|
||||
writel(INTEN_RISE1 | INTEN_RISE2, ®->inten);
|
||||
}
|
||||
|
||||
/*
|
||||
* Initialize TMU device
|
||||
*
|
||||
* @return int value, 0 for success
|
||||
*/
|
||||
int tmu_init(struct tmu_info *info)
|
||||
{
|
||||
info->tmu_state = TMU_STATUS_INIT;
|
||||
|
||||
tmu_setup_parameters(info);
|
||||
info->tmu_state = TMU_STATUS_NORMAL;
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,134 @@
|
|||
/*
|
||||
* This file is part of the coreboot project.
|
||||
*
|
||||
* Copyright (c) 2012 Samsung Electronics Co., Ltd.
|
||||
*
|
||||
* 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; version 2 of 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
/* EXYNOS - Thermal Management Unit */
|
||||
|
||||
#ifndef CPU_SAMSUNG_EXYNOS5420_TMU_H
|
||||
#define CPU_SAMSUNG_EXYNOS5420_TMU_H
|
||||
|
||||
struct tmu_reg {
|
||||
unsigned triminfo;
|
||||
unsigned rsvd1;
|
||||
unsigned rsvd2;
|
||||
unsigned rsvd3;
|
||||
unsigned rsvd4;
|
||||
unsigned triminfo_control;
|
||||
unsigned rsvd5;
|
||||
unsigned rsvd6;
|
||||
unsigned tmu_control;
|
||||
unsigned rsvd7;
|
||||
unsigned tmu_status;
|
||||
unsigned sampling_internal;
|
||||
unsigned counter_value0;
|
||||
unsigned counter_value1;
|
||||
unsigned rsvd8;
|
||||
unsigned rsvd9;
|
||||
unsigned current_temp;
|
||||
unsigned rsvd10;
|
||||
unsigned rsvd11;
|
||||
unsigned rsvd12;
|
||||
unsigned threshold_temp_rise;
|
||||
unsigned threshold_temp_fall;
|
||||
unsigned rsvd13;
|
||||
unsigned rsvd14;
|
||||
unsigned past_temp3_0;
|
||||
unsigned past_temp7_4;
|
||||
unsigned past_temp11_8;
|
||||
unsigned past_temp15_12;
|
||||
unsigned inten;
|
||||
unsigned intstat;
|
||||
unsigned intclear;
|
||||
unsigned rsvd15;
|
||||
unsigned emul_con;
|
||||
};
|
||||
|
||||
enum tmu_status_t {
|
||||
TMU_STATUS_INIT = 0,
|
||||
TMU_STATUS_NORMAL,
|
||||
TMU_STATUS_WARNING,
|
||||
TMU_STATUS_TRIPPED,
|
||||
};
|
||||
|
||||
/* Tmeperature threshold values for various thermal events */
|
||||
struct temperature_params {
|
||||
/* minimum value in temperature code range */
|
||||
unsigned int min_val;
|
||||
/* maximum value in temperature code range */
|
||||
unsigned int max_val;
|
||||
/* temperature threshold to start warning */
|
||||
unsigned int start_warning;
|
||||
/* temperature threshold CPU tripping */
|
||||
unsigned int start_tripping;
|
||||
/* temperature threshold for HW tripping */
|
||||
unsigned int hardware_tripping;
|
||||
};
|
||||
|
||||
/* Pre-defined values and thresholds for calibration of current temperature */
|
||||
struct tmu_data {
|
||||
/* pre-defined temperature thresholds */
|
||||
struct temperature_params ts;
|
||||
/* pre-defined efuse range minimum value */
|
||||
unsigned int efuse_min_value;
|
||||
/* pre-defined efuse value for temperature calibration */
|
||||
unsigned int efuse_value;
|
||||
/* pre-defined efuse range maximum value */
|
||||
unsigned int efuse_max_value;
|
||||
/* current temperature sensing slope */
|
||||
unsigned int slope;
|
||||
};
|
||||
|
||||
/* TMU device specific details and status */
|
||||
struct tmu_info {
|
||||
/* base Address for the TMU */
|
||||
unsigned tmu_base;
|
||||
/* mux Address for the TMU */
|
||||
int tmu_mux;
|
||||
/* pre-defined values for calibration and thresholds */
|
||||
struct tmu_data data;
|
||||
/* value required for triminfo_25 calibration */
|
||||
unsigned int te1;
|
||||
/* value required for triminfo_85 calibration */
|
||||
unsigned int te2;
|
||||
/* TMU DC value for threshold calculation */
|
||||
int dc_value;
|
||||
/* enum value indicating status of the TMU */
|
||||
int tmu_state;
|
||||
};
|
||||
|
||||
extern struct tmu_info *tmu_info;
|
||||
|
||||
/*
|
||||
* Monitors status of the TMU device and exynos temperature
|
||||
*
|
||||
* @info pointer to TMU info struct
|
||||
* @temp pointer to the current temperature value
|
||||
* @return enum tmu_status_t value, code indicating event to execute
|
||||
* and -1 on error
|
||||
*/
|
||||
enum tmu_status_t tmu_monitor(struct tmu_info *info, int *temp);
|
||||
|
||||
/*
|
||||
* Initialize TMU device
|
||||
*
|
||||
* @info pointer to TMU info struct
|
||||
* @return int value, 0 for success
|
||||
*/
|
||||
int tmu_init(struct tmu_info *info);
|
||||
|
||||
#endif /* CPU_SAMSUNG_EXYNOS5420_TMU_H */
|
|
@ -0,0 +1,200 @@
|
|||
/*
|
||||
* This file is part of the coreboot project.
|
||||
*
|
||||
* Copyright (C) 2009 Samsung Electronics
|
||||
*
|
||||
* 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; version 2 of 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include <console/console.h> /* for __console definition */
|
||||
#include <uart.h>
|
||||
#include <arch/io.h>
|
||||
#include "uart.h"
|
||||
#include "clk.h"
|
||||
#include "cpu.h"
|
||||
|
||||
#define RX_FIFO_COUNT_MASK 0xff
|
||||
#define RX_FIFO_FULL_MASK (1 << 8)
|
||||
#define TX_FIFO_FULL_MASK (1 << 24)
|
||||
|
||||
/* FIXME(dhendrix): exynos5 has 4 UARTs and its functions in u-boot take a
|
||||
base_port argument. However console_driver functions do not. */
|
||||
static uint32_t base_port = CONFIG_CONSOLE_SERIAL_UART_ADDRESS;
|
||||
|
||||
/*
|
||||
* The coefficient, used to calculate the baudrate on S5P UARTs is
|
||||
* calculated as
|
||||
* C = UBRDIV * 16 + number_of_set_bits_in_UDIVSLOT
|
||||
* however, section 31.6.11 of the datasheet doesn't recomment using 1 for 1,
|
||||
* 3 for 2, ... (2^n - 1) for n, instead, they suggest using these constants:
|
||||
*/
|
||||
static const int udivslot[] = {
|
||||
0,
|
||||
0x0080,
|
||||
0x0808,
|
||||
0x0888,
|
||||
0x2222,
|
||||
0x4924,
|
||||
0x4a52,
|
||||
0x54aa,
|
||||
0x5555,
|
||||
0xd555,
|
||||
0xd5d5,
|
||||
0xddd5,
|
||||
0xdddd,
|
||||
0xdfdd,
|
||||
0xdfdf,
|
||||
0xffdf,
|
||||
};
|
||||
|
||||
static void serial_setbrg_dev(void)
|
||||
{
|
||||
struct s5p_uart *uart = (struct s5p_uart *)base_port;
|
||||
u32 uclk;
|
||||
u32 baudrate = CONFIG_TTYS0_BAUD;
|
||||
u32 val;
|
||||
|
||||
// All UARTs share the same clock.
|
||||
uclk = clock_get_periph_rate(PERIPH_ID_UART3);
|
||||
val = uclk / baudrate;
|
||||
|
||||
writel(val / 16 - 1, &uart->ubrdiv);
|
||||
|
||||
/*
|
||||
* FIXME(dhendrix): the original uart.h had a "br_rest" value which
|
||||
* does not seem relevant to the exynos5420... not entirely sure
|
||||
* where/if we need to worry about it here
|
||||
*/
|
||||
#if 0
|
||||
if (s5p_uart_divslot())
|
||||
writel(udivslot[val % 16], &uart->rest.slot);
|
||||
else
|
||||
writeb(val % 16, &uart->rest.value);
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
* Initialise the serial port with the given baudrate. The settings
|
||||
* are always 8 data bits, no parity, 1 stop bit, no start bits.
|
||||
*/
|
||||
static void exynos5_init_dev(void)
|
||||
{
|
||||
struct s5p_uart *uart = (struct s5p_uart *)base_port;
|
||||
|
||||
// TODO initialize with correct peripheral id by base_port.
|
||||
exynos_pinmux_config(PERIPH_ID_UART3, PINMUX_FLAG_NONE);
|
||||
|
||||
/* enable FIFOs */
|
||||
writel(0x1, &uart->ufcon);
|
||||
writel(0, &uart->umcon);
|
||||
/* 8N1 */
|
||||
writel(0x3, &uart->ulcon);
|
||||
/* No interrupts, no DMA, pure polling */
|
||||
writel(0x245, &uart->ucon);
|
||||
|
||||
serial_setbrg_dev();
|
||||
}
|
||||
|
||||
static int exynos5_uart_err_check(int op)
|
||||
{
|
||||
struct s5p_uart *uart = (struct s5p_uart *)base_port;
|
||||
unsigned int mask;
|
||||
|
||||
/*
|
||||
* UERSTAT
|
||||
* Break Detect [3]
|
||||
* Frame Err [2] : receive operation
|
||||
* Parity Err [1] : receive operation
|
||||
* Overrun Err [0] : receive operation
|
||||
*/
|
||||
if (op)
|
||||
mask = 0x8;
|
||||
else
|
||||
mask = 0xf;
|
||||
|
||||
return readl(&uart->uerstat) & mask;
|
||||
}
|
||||
|
||||
/*
|
||||
* Read a single byte from the serial port. Returns 1 on success, 0
|
||||
* otherwise. When the function is succesfull, the character read is
|
||||
* written into its argument c.
|
||||
*/
|
||||
static unsigned char exynos5_uart_rx_byte(void)
|
||||
{
|
||||
struct s5p_uart *uart = (struct s5p_uart *)base_port;
|
||||
|
||||
/* wait for character to arrive */
|
||||
while (!(readl(&uart->ufstat) & (RX_FIFO_COUNT_MASK |
|
||||
RX_FIFO_FULL_MASK))) {
|
||||
if (exynos5_uart_err_check(0))
|
||||
return 0;
|
||||
}
|
||||
|
||||
return readb(&uart->urxh) & 0xff;
|
||||
}
|
||||
|
||||
/*
|
||||
* Output a single byte to the serial port.
|
||||
*/
|
||||
static void exynos5_uart_tx_byte(unsigned char data)
|
||||
{
|
||||
struct s5p_uart *uart = (struct s5p_uart *)base_port;
|
||||
|
||||
/* wait for room in the tx FIFO */
|
||||
while ((readl(&uart->ufstat) & TX_FIFO_FULL_MASK)) {
|
||||
if (exynos5_uart_err_check(1))
|
||||
return;
|
||||
}
|
||||
|
||||
writeb(data, &uart->utxh);
|
||||
}
|
||||
|
||||
#if !defined(__PRE_RAM__)
|
||||
|
||||
static const struct console_driver exynos5_uart_console __console = {
|
||||
.init = exynos5_init_dev,
|
||||
.tx_byte = exynos5_uart_tx_byte,
|
||||
// .tx_flush = exynos5_uart_tx_flush,
|
||||
.rx_byte = exynos5_uart_rx_byte,
|
||||
// .tst_byte = exynos5_uart_tst_byte,
|
||||
};
|
||||
|
||||
uint32_t uartmem_getbaseaddr(void)
|
||||
{
|
||||
return base_port;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
void uart_init(void)
|
||||
{
|
||||
exynos5_init_dev();
|
||||
}
|
||||
|
||||
unsigned char uart_rx_byte(void)
|
||||
{
|
||||
return exynos5_uart_rx_byte();
|
||||
}
|
||||
|
||||
void uart_tx_byte(unsigned char data)
|
||||
{
|
||||
exynos5_uart_tx_byte(data);
|
||||
}
|
||||
|
||||
void uart_tx_flush(void)
|
||||
{
|
||||
}
|
||||
|
||||
#endif
|
|
@ -0,0 +1,54 @@
|
|||
/*
|
||||
* This file is part of the coreboot project.
|
||||
*
|
||||
* Copyright 2012 Google Inc.
|
||||
* Copyright (C) 2009 Samsung Electronics
|
||||
*
|
||||
* 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; version 2 of 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#ifndef CPU_SAMSUNG_EXYNOS5420_UART_H
|
||||
#define CPU_SAMSUNG_EXYNOS5420_UART_H
|
||||
|
||||
#define EXYNOS5_UART0_BASE 0x12c00000
|
||||
#define EXYNOS5_UART1_BASE 0x12c10000
|
||||
#define EXYNOS5_UART2_BASE 0x12c20000
|
||||
#define EXYNOS5_UART3_BASE 0x12c30000
|
||||
#define EXYNOS5_ISP_UART_BASE 0x13190000
|
||||
|
||||
/* baudrate rest value */
|
||||
union br_rest {
|
||||
unsigned short slot; /* udivslot */
|
||||
unsigned char value; /* ufracval */
|
||||
};
|
||||
|
||||
struct s5p_uart {
|
||||
unsigned int ulcon;
|
||||
unsigned int ucon;
|
||||
unsigned int ufcon;
|
||||
unsigned int umcon;
|
||||
unsigned int utrstat;
|
||||
unsigned int uerstat;
|
||||
unsigned int ufstat;
|
||||
unsigned int umstat;
|
||||
unsigned char utxh;
|
||||
unsigned char res1[3];
|
||||
unsigned char urxh;
|
||||
unsigned char res2[3];
|
||||
unsigned int ubrdiv;
|
||||
union br_rest rest;
|
||||
unsigned char res3[0xffd0];
|
||||
};
|
||||
|
||||
#endif
|
|
@ -0,0 +1,50 @@
|
|||
/*
|
||||
* This file is part of the coreboot project.
|
||||
*
|
||||
* Copyright 2013 Google Inc.
|
||||
*
|
||||
* 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; version 2 of 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include <console/console.h>
|
||||
#include "power.h"
|
||||
#include "wakeup.h"
|
||||
|
||||
void wakeup(void)
|
||||
{
|
||||
if (wakeup_need_reset())
|
||||
power_reset();
|
||||
|
||||
power_init(); /* Ensure ps_hold_setup() for early wakeup. */
|
||||
power_exit_wakeup();
|
||||
/* Should never return. */
|
||||
die("Failed to wake up.\n");
|
||||
}
|
||||
|
||||
int get_wakeup_state(void)
|
||||
{
|
||||
uint32_t status = power_read_reset_status();
|
||||
|
||||
/* DIDLE/LPA can be resumed without clock reset (ex, bootblock),
|
||||
* and SLEEP requires resetting clock (should be done in ROM stage).
|
||||
*/
|
||||
|
||||
if (status == S5P_CHECK_DIDLE || status == S5P_CHECK_LPA)
|
||||
return WAKEUP_DIRECT;
|
||||
|
||||
if (status == S5P_CHECK_SLEEP)
|
||||
return WAKEUP_NEED_CLOCK_RESET;
|
||||
|
||||
return IS_NOT_WAKEUP;
|
||||
}
|
|
@ -0,0 +1,42 @@
|
|||
/*
|
||||
* This file is part of the coreboot project.
|
||||
*
|
||||
* Copyright 2013 Google Inc.
|
||||
*
|
||||
* 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; version 2 of 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#ifndef CPU_SAMSUNG_EXYNOS5420_WAKEUP_H
|
||||
#define CPU_SAMSUNG_EXYNOS5420_WAKEUP_H
|
||||
|
||||
/* Power Down Modes */
|
||||
#define S5P_CHECK_SLEEP 0x00000BAD
|
||||
#define S5P_CHECK_DIDLE 0xBAD00000
|
||||
#define S5P_CHECK_LPA 0xABAD0000
|
||||
|
||||
enum {
|
||||
// A normal boot (not suspend/resume)
|
||||
IS_NOT_WAKEUP,
|
||||
// A wake up event that can be resumed any time
|
||||
WAKEUP_DIRECT,
|
||||
// A wake up event that must be resumed only after
|
||||
// clock and memory controllers are re-initialized
|
||||
WAKEUP_NEED_CLOCK_RESET,
|
||||
};
|
||||
|
||||
int wakeup_need_reset(void);
|
||||
int get_wakeup_state(void);
|
||||
void wakeup(void);
|
||||
|
||||
#endif /* CPU_SAMSUNG_EXYNOS5420_WAKEUP_H */
|
|
@ -22,7 +22,7 @@ if BOARD_GOOGLE_SNOW
|
|||
config BOARD_SPECIFIC_OPTIONS # dummy
|
||||
def_bool y
|
||||
select ARCH_ARMV7
|
||||
select CPU_SAMSUNG_EXYNOS5
|
||||
select CPU_SAMSUNG_EXYNOS5250
|
||||
select HAVE_UART_MEMORY_MAPPED
|
||||
select EC_GOOGLE_CHROMEEC
|
||||
select EC_GOOGLE_CHROMEEC_I2C
|
||||
|
|
Loading…
Reference in New Issue