From b98dec032f0d8ee158e606bceef9766a905ad503 Mon Sep 17 00:00:00 2001 From: Stefan Reinauer Date: Tue, 14 May 2013 13:32:33 -0700 Subject: samsung/exynos5250: unify code It turns out that the exynos5-common code previously imported from u-boot is not common code at all but very specific to the 5250 and not compatible with the 5450. Hence, unify the directories exynos5250 and exynos5-common. We will try to factor out common code while progressing with the 5450 port. Change-Id: Iab595e66fcd01eda8365c96fb8bef896f7602f03 Signed-off-by: Stefan Reinauer Signed-off-by: Gabe Black Reviewed-on: http://review.coreboot.org/3641 Tested-by: build bot (Jenkins) Reviewed-by: Stefan Reinauer --- src/cpu/samsung/Makefile.inc | 1 - src/cpu/samsung/exynos5-common/Makefile.inc | 24 - src/cpu/samsung/exynos5-common/adc.h | 42 -- src/cpu/samsung/exynos5-common/clk.h | 70 --- src/cpu/samsung/exynos5-common/clock.h | 94 ---- src/cpu/samsung/exynos5-common/cpu.h | 128 ----- src/cpu/samsung/exynos5-common/cpu_info.c | 66 --- src/cpu/samsung/exynos5-common/exynos-fb.c | 606 ------------------------ src/cpu/samsung/exynos5-common/exynos-tmu.c | 195 -------- src/cpu/samsung/exynos5-common/exynos-tmu.h | 132 ------ src/cpu/samsung/exynos5-common/exynos5-common.h | 45 -- src/cpu/samsung/exynos5-common/gpio.c | 501 -------------------- src/cpu/samsung/exynos5-common/gpio.h | 285 ----------- src/cpu/samsung/exynos5-common/i2c.c | 414 ---------------- src/cpu/samsung/exynos5-common/i2c.h | 45 -- src/cpu/samsung/exynos5-common/power.h | 45 -- src/cpu/samsung/exynos5-common/pwm.c | 199 -------- src/cpu/samsung/exynos5-common/pwm.h | 74 --- src/cpu/samsung/exynos5-common/reset.c | 30 -- src/cpu/samsung/exynos5-common/s5p-dp-core.h | 257 ---------- src/cpu/samsung/exynos5-common/s5p-dp-reg.c | 486 ------------------- src/cpu/samsung/exynos5-common/spi.c | 227 --------- src/cpu/samsung/exynos5-common/spi.h | 102 ---- src/cpu/samsung/exynos5-common/sromc.c | 49 -- src/cpu/samsung/exynos5-common/sromc.h | 69 --- src/cpu/samsung/exynos5-common/timer.c | 164 ------- src/cpu/samsung/exynos5-common/uart.h | 55 --- src/cpu/samsung/exynos5-common/watchdog.h | 57 --- src/cpu/samsung/exynos5-common/wdt.c | 59 --- src/cpu/samsung/exynos5250/Makefile.inc | 21 +- src/cpu/samsung/exynos5250/adc.h | 42 ++ src/cpu/samsung/exynos5250/clk.h | 45 +- src/cpu/samsung/exynos5250/clock.c | 1 - src/cpu/samsung/exynos5250/clock.h | 94 ++++ src/cpu/samsung/exynos5250/clock_init.c | 1 - src/cpu/samsung/exynos5250/cpu.c | 4 +- src/cpu/samsung/exynos5250/cpu.h | 100 +++- src/cpu/samsung/exynos5250/cpu_info.c | 64 +++ src/cpu/samsung/exynos5250/dmc_init_ddr3.c | 3 +- src/cpu/samsung/exynos5250/exynos-fb.c | 606 ++++++++++++++++++++++++ src/cpu/samsung/exynos5250/exynos-tmu.c | 195 ++++++++ src/cpu/samsung/exynos5250/exynos-tmu.h | 132 ++++++ src/cpu/samsung/exynos5250/exynos5-common.h | 45 ++ src/cpu/samsung/exynos5250/exynos5250-tmu.c | 2 +- src/cpu/samsung/exynos5250/gpio.c | 500 +++++++++++++++++++ src/cpu/samsung/exynos5250/gpio.h | 236 ++++++++- src/cpu/samsung/exynos5250/i2c.c | 414 ++++++++++++++++ src/cpu/samsung/exynos5250/i2c.h | 45 ++ src/cpu/samsung/exynos5250/pinmux.c | 2 +- src/cpu/samsung/exynos5250/power.c | 1 - src/cpu/samsung/exynos5250/power.h | 19 + src/cpu/samsung/exynos5250/pwm.c | 199 ++++++++ src/cpu/samsung/exynos5250/pwm.h | 74 +++ src/cpu/samsung/exynos5250/reset.c | 30 ++ src/cpu/samsung/exynos5250/s5p-dp-core.h | 259 ++++++++++ src/cpu/samsung/exynos5250/s5p-dp-reg.c | 486 +++++++++++++++++++ src/cpu/samsung/exynos5250/spi.c | 227 +++++++++ src/cpu/samsung/exynos5250/spi.h | 14 + src/cpu/samsung/exynos5250/sromc.c | 49 ++ src/cpu/samsung/exynos5250/sromc.h | 69 +++ src/cpu/samsung/exynos5250/timer.c | 164 +++++++ src/cpu/samsung/exynos5250/uart.c | 3 +- src/cpu/samsung/exynos5250/uart.h | 29 ++ src/cpu/samsung/exynos5250/wakeup.c | 2 +- src/cpu/samsung/exynos5250/watchdog.h | 57 +++ src/cpu/samsung/exynos5250/wdt.c | 59 +++ 66 files changed, 4277 insertions(+), 4537 deletions(-) delete mode 100644 src/cpu/samsung/exynos5-common/Makefile.inc delete mode 100644 src/cpu/samsung/exynos5-common/adc.h delete mode 100644 src/cpu/samsung/exynos5-common/clk.h delete mode 100644 src/cpu/samsung/exynos5-common/clock.h delete mode 100644 src/cpu/samsung/exynos5-common/cpu.h delete mode 100644 src/cpu/samsung/exynos5-common/cpu_info.c delete mode 100644 src/cpu/samsung/exynos5-common/exynos-fb.c delete mode 100644 src/cpu/samsung/exynos5-common/exynos-tmu.c delete mode 100644 src/cpu/samsung/exynos5-common/exynos-tmu.h delete mode 100644 src/cpu/samsung/exynos5-common/exynos5-common.h delete mode 100644 src/cpu/samsung/exynos5-common/gpio.c delete mode 100644 src/cpu/samsung/exynos5-common/gpio.h delete mode 100644 src/cpu/samsung/exynos5-common/i2c.c delete mode 100644 src/cpu/samsung/exynos5-common/i2c.h delete mode 100644 src/cpu/samsung/exynos5-common/power.h delete mode 100644 src/cpu/samsung/exynos5-common/pwm.c delete mode 100644 src/cpu/samsung/exynos5-common/pwm.h delete mode 100644 src/cpu/samsung/exynos5-common/reset.c delete mode 100644 src/cpu/samsung/exynos5-common/s5p-dp-core.h delete mode 100644 src/cpu/samsung/exynos5-common/s5p-dp-reg.c delete mode 100644 src/cpu/samsung/exynos5-common/spi.c delete mode 100644 src/cpu/samsung/exynos5-common/spi.h delete mode 100644 src/cpu/samsung/exynos5-common/sromc.c delete mode 100644 src/cpu/samsung/exynos5-common/sromc.h delete mode 100644 src/cpu/samsung/exynos5-common/timer.c delete mode 100644 src/cpu/samsung/exynos5-common/uart.h delete mode 100644 src/cpu/samsung/exynos5-common/watchdog.h delete mode 100644 src/cpu/samsung/exynos5-common/wdt.c create mode 100644 src/cpu/samsung/exynos5250/adc.h create mode 100644 src/cpu/samsung/exynos5250/clock.h create mode 100644 src/cpu/samsung/exynos5250/cpu_info.c create mode 100644 src/cpu/samsung/exynos5250/exynos-fb.c create mode 100644 src/cpu/samsung/exynos5250/exynos-tmu.c create mode 100644 src/cpu/samsung/exynos5250/exynos-tmu.h create mode 100644 src/cpu/samsung/exynos5250/exynos5-common.h create mode 100644 src/cpu/samsung/exynos5250/gpio.c create mode 100644 src/cpu/samsung/exynos5250/i2c.c create mode 100644 src/cpu/samsung/exynos5250/i2c.h create mode 100644 src/cpu/samsung/exynos5250/pwm.c create mode 100644 src/cpu/samsung/exynos5250/pwm.h create mode 100644 src/cpu/samsung/exynos5250/reset.c create mode 100644 src/cpu/samsung/exynos5250/s5p-dp-core.h create mode 100644 src/cpu/samsung/exynos5250/s5p-dp-reg.c create mode 100644 src/cpu/samsung/exynos5250/spi.c create mode 100644 src/cpu/samsung/exynos5250/sromc.c create mode 100644 src/cpu/samsung/exynos5250/sromc.h create mode 100644 src/cpu/samsung/exynos5250/timer.c create mode 100644 src/cpu/samsung/exynos5250/watchdog.h create mode 100644 src/cpu/samsung/exynos5250/wdt.c (limited to 'src/cpu/samsung') diff --git a/src/cpu/samsung/Makefile.inc b/src/cpu/samsung/Makefile.inc index 97e9aab148..91109834b3 100644 --- a/src/cpu/samsung/Makefile.inc +++ b/src/cpu/samsung/Makefile.inc @@ -1,2 +1 @@ -subdirs-$(CONFIG_CPU_SAMSUNG_EXYNOS5) += exynos5-common subdirs-$(CONFIG_CPU_SAMSUNG_EXYNOS5) += exynos5250 diff --git a/src/cpu/samsung/exynos5-common/Makefile.inc b/src/cpu/samsung/exynos5-common/Makefile.inc deleted file mode 100644 index 6331863440..0000000000 --- a/src/cpu/samsung/exynos5-common/Makefile.inc +++ /dev/null @@ -1,24 +0,0 @@ -romstage-y += spi.c -ramstage-y += spi.c -bootblock-y += spi.c - -bootblock-y += gpio.c -bootblock-$(CONFIG_EARLY_CONSOLE) += pwm.c -bootblock-$(CONFIG_EARLY_CONSOLE) += timer.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 -#romstage-y += sromc.c - -ramstage-y += cpu_info.c -ramstage-y += pwm.c # needed by timer.c -ramstage-y += timer.c -ramstage-y += gpio.c -ramstage-y += i2c.c -ramstage-y += s5p-dp-reg.c -ramstage-y += exynos-fb.c -ramstage-y += exynos-tmu.c diff --git a/src/cpu/samsung/exynos5-common/adc.h b/src/cpu/samsung/exynos5-common/adc.h deleted file mode 100644 index 64f4813495..0000000000 --- a/src/cpu/samsung/exynos5-common/adc.h +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Copyright (C) 2010 Samsung Electronics - * Minkyu Kang - * MyungJoo Ham - * - * See file CREDITS for list of people who contributed to this - * project. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of - * the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, - * MA 02111-1307 USA - */ - -#ifndef __ASM_ARM_ARCH_COMMON_ADC_H_ -#define __ASM_ARM_ARCH_COMMON_ADC_H_ - -#ifndef __ASSEMBLER__ -struct s5p_adc { - unsigned int adccon; - unsigned int adctsc; - unsigned int adcdly; - unsigned int adcdat0; - unsigned int adcdat1; - unsigned int adcupdn; - unsigned int adcclrint; - unsigned int adcmux; - unsigned int adcclrintpndnup; -}; -#endif - -#endif /* __ASM_ARM_ARCH_COMMON_ADC_H_ */ diff --git a/src/cpu/samsung/exynos5-common/clk.h b/src/cpu/samsung/exynos5-common/clk.h deleted file mode 100644 index 9de4f45516..0000000000 --- a/src/cpu/samsung/exynos5-common/clk.h +++ /dev/null @@ -1,70 +0,0 @@ -/* - * (C) Copyright 2012 The Chromium Authors - * (C) Copyright 2010 Samsung Electronics - * Minkyu Kang - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of - * the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, - * MA 02111-1307 USA - * - */ - -#ifndef __EXYNOS_COMMON_CLK_H_ -#define __EXYNOS_COMMON_CLK_H_ - -#include -#include - -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); - -#endif diff --git a/src/cpu/samsung/exynos5-common/clock.h b/src/cpu/samsung/exynos5-common/clock.h deleted file mode 100644 index c0cd896b22..0000000000 --- a/src/cpu/samsung/exynos5-common/clock.h +++ /dev/null @@ -1,94 +0,0 @@ -/* - * (C) Copyright 2009 Samsung Electronics - * Minkyu Kang - * Heungjun Kim - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of - * the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, - * MA 02111-1307 USA - * - */ - -#ifndef __ASM_ARM_ARCH_CLOCK_H_ -#define __ASM_ARM_ARCH_CLOCK_H_ - -#ifndef __ASSEMBLER__ -struct s5pc100_clock { - unsigned int apll_lock; - unsigned int mpll_lock; - unsigned int epll_lock; - unsigned int hpll_lock; - unsigned char res1[0xf0]; - unsigned int apll_con; - unsigned int mpll_con; - unsigned int epll_con; - unsigned int hpll_con; - unsigned char res2[0xf0]; - unsigned int src0; - unsigned int src1; - unsigned int src2; - unsigned int src3; - unsigned char res3[0xf0]; - unsigned int div0; - unsigned int div1; - unsigned int div2; - unsigned int div3; - unsigned int div4; - unsigned char res4[0x1ec]; - unsigned int gate_d00; - unsigned int gate_d01; - unsigned int gate_d02; - unsigned char res5[0x54]; - unsigned int gate_sclk0; - unsigned int gate_sclk1; -}; - -struct s5pc110_clock { - unsigned int apll_lock; - unsigned char res1[0x4]; - unsigned int mpll_lock; - unsigned char res2[0x4]; - unsigned int epll_lock; - unsigned char res3[0xc]; - unsigned int vpll_lock; - unsigned char res4[0xdc]; - unsigned int apll_con; - unsigned char res5[0x4]; - unsigned int mpll_con; - unsigned char res6[0x4]; - unsigned int epll_con; - unsigned char res7[0xc]; - unsigned int vpll_con; - unsigned char res8[0xdc]; - unsigned int src0; - unsigned int src1; - unsigned int src2; - unsigned int src3; - unsigned char res9[0xf0]; - unsigned int div0; - unsigned int div1; - unsigned int div2; - unsigned int div3; - unsigned int div4; - unsigned char res10[0x1ec]; - unsigned int gate_d00; - unsigned int gate_d01; - unsigned int gate_d02; - unsigned char res11[0x54]; - unsigned int gate_sclk0; - unsigned int gate_sclk1; -}; -#endif - -#endif diff --git a/src/cpu/samsung/exynos5-common/cpu.h b/src/cpu/samsung/exynos5-common/cpu.h deleted file mode 100644 index 8856ddb71a..0000000000 --- a/src/cpu/samsung/exynos5-common/cpu.h +++ /dev/null @@ -1,128 +0,0 @@ -/* - * (C) Copyright 2009-2010 Samsung Electronics - * Minkyu Kang - * Heungjun Kim - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of - * the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, - * MA 02111-1307 USA - * - */ - -#ifndef _EXYNOS_COMMON_CPU_H -#define _EXYNOS_COMMON_CPU_H - -#define S5PC1XX_ADDR_BASE 0xE0000000 - -/* S5PC100 */ -#define S5PC100_PRO_ID 0xE0000000 -#define S5PC100_CLOCK_BASE 0xE0100000 -#define S5PC100_GPIO_BASE 0xE0300000 -#define S5PC100_VIC0_BASE 0xE4000000 -#define S5PC100_VIC1_BASE 0xE4100000 -#define S5PC100_VIC2_BASE 0xE4200000 -#define S5PC100_DMC_BASE 0xE6000000 -#define S5PC100_SROMC_BASE 0xE7000000 -#define S5PC100_ONENAND_BASE 0xE7100000 -#define S5PC100_PWMTIMER_BASE 0xEA000000 -#define S5PC100_WATCHDOG_BASE 0xEA200000 -#define S5PC100_UART_BASE 0xEC000000 -#define S5PC100_MMC_BASE 0xED800000 - -/* S5PC110 */ -#define S5PC110_PRO_ID 0xE0000000 -#define S5PC110_CLOCK_BASE 0xE0100000 -#define S5PC110_GPIO_BASE 0xE0200000 -#define S5PC110_PWMTIMER_BASE 0xE2500000 -#define S5PC110_WATCHDOG_BASE 0xE2700000 -#define S5PC110_UART_BASE 0xE2900000 -#define S5PC110_SROMC_BASE 0xE8000000 -#define S5PC110_MMC_BASE 0xEB000000 -#define S5PC110_DMC0_BASE 0xF0000000 -#define S5PC110_DMC1_BASE 0xF1400000 -#define S5PC110_VIC0_BASE 0xF2000000 -#define S5PC110_VIC1_BASE 0xF2100000 -#define S5PC110_VIC2_BASE 0xF2200000 -#define S5PC110_VIC3_BASE 0xF2300000 -#define S5PC110_OTG_BASE 0xEC000000 -#define S5PC110_PHY_BASE 0xEC100000 -#define S5PC110_USB_PHY_CONTROL 0xE010E80C - - -#include - -#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 - -enum boot_mode { - /* - * Assign the OM pin values for respective boot modes. - * Exynos4 does not support spi boot and the mmc boot OM - * pin values are the same across Exynos4 and Exynos5. - */ - BOOT_MODE_MMC = 4, - BOOT_MODE_SERIAL = 20, - /* Boot based on Operating Mode pin settings */ - BOOT_MODE_OM = 32, - BOOT_MODE_USB, /* Boot using USB download */ -}; - -/** - * Get the boot device containing BL1, BL2 (SPL) and U-boot - * - * @return boot device - */ -enum boot_mode exynos_get_boot_device(void); - -/** - * Check if a wakeup is permitted. - * - * On some boards we need to look at a special GPIO to ensure that the wakeup - * from sleep was valid. If the wakeup is not valid we need to go through a - * full reset. - * - * The default implementation of this function allows all wakeups. - * - * @return 1 if wakeup is permitted; 0 otherwise - */ -int board_wakeup_permitted(void); - -/** - * Init subsystems according to the reset status - * - * @return 0 for a normal boot, non-zero for a resume - */ -int lowlevel_init_subsystems(void); - -int arch_cpu_init(void); - - -#endif /* _EXYNOS_COMMON_CPU_H */ diff --git a/src/cpu/samsung/exynos5-common/cpu_info.c b/src/cpu/samsung/exynos5-common/cpu_info.c deleted file mode 100644 index ca9454ef61..0000000000 --- a/src/cpu/samsung/exynos5-common/cpu_info.c +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Copyright (C) 2009 Samsung Electronics - * Minkyu Kang - * - * See file CREDITS for list of people who contributed to this - * project. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of - * the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, - * MA 02111-1307 USA - */ - -#include -#include -#include - -#include -#include -#include - -#include -#include /* for EXYNOS_PRO_ID */ - -/* FIXME(dhendrix): consolidate samsung ID code/#defines to a common location */ -#include /* cpu_info_init() prototype */ - -static unsigned int s5p_cpu_id; -static unsigned int s5p_cpu_rev; - -static void s5p_set_cpu_id(void) -{ - s5p_cpu_id = readl((void *)EXYNOS_PRO_ID); - s5p_cpu_id = (0xC000 | ((s5p_cpu_id & 0x00FFF000) >> 12)); - - /* - * 0xC200: EXYNOS4210 EVT0 - * 0xC210: EXYNOS4210 EVT1 - */ - if (s5p_cpu_id == 0xC200) { - s5p_cpu_id |= 0x10; - s5p_cpu_rev = 0; - } else if (s5p_cpu_id == 0xC210) { - s5p_cpu_rev = 1; - } -} - -int arch_cpu_init(void) -{ - s5p_set_cpu_id(); - - printk(BIOS_INFO, "CPU: S5P%X @ %ldMHz\n", - s5p_cpu_id, get_arm_clk() / (1024*1024)); - - return 0; -} diff --git a/src/cpu/samsung/exynos5-common/exynos-fb.c b/src/cpu/samsung/exynos5-common/exynos-fb.c deleted file mode 100644 index b2e926f77d..0000000000 --- a/src/cpu/samsung/exynos5-common/exynos-fb.c +++ /dev/null @@ -1,606 +0,0 @@ -/* - * LCD driver for Exynos - * - * Copyright 2013 Google Inc. - * Copyright (C) 2012 Samsung Electronics - * - * See file CREDITS for list of people who contributed to this - * project. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of - * the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, - * MA 02111-1307 USA - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "device/i2c.h" -#include "cpu/samsung/exynos5-common/i2c.h" -#include "cpu/samsung/exynos5250/dsim.h" -#include "cpu/samsung/exynos5250/fimd.h" - -#include "cpu/samsung/exynos5250/s5p-dp.h" -#include "s5p-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; - - -#ifdef CONFIG_EXYNOS_DISPLAYPORT -static struct s5p_dp_device dp_device; - -#endif - -/* 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<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); -} - -void exynos_fimd_disable(void); -void exynos_fimd_disable(void) -{ - struct exynos5_fimd *fimd = samsung_get_base_fimd(); - - writel(0, &fimd->wincon0); - clrbits_le32(&fimd->shadowcon, CHANNEL0_EN); -} - -/* - * 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; -} diff --git a/src/cpu/samsung/exynos5-common/exynos-tmu.c b/src/cpu/samsung/exynos5-common/exynos-tmu.c deleted file mode 100644 index 26777fca23..0000000000 --- a/src/cpu/samsung/exynos5-common/exynos-tmu.c +++ /dev/null @@ -1,195 +0,0 @@ -/* - * Copyright (c) 2012 Samsung Electronics Co., Ltd. - * http://www.samsung.com - * Akshay Saraswat - * Copyright (c) 2013 Google Inc. - * - * EXYNOS - Thermal Management Unit - * - * This file was originally imported from Das U-Boot and then re-factored - * for coreboot. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, - * MA 02111-1307 USA - */ - -#include -#include -#include - -#include - -#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) - -/* - * 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; -} diff --git a/src/cpu/samsung/exynos5-common/exynos-tmu.h b/src/cpu/samsung/exynos5-common/exynos-tmu.h deleted file mode 100644 index 40eda5626e..0000000000 --- a/src/cpu/samsung/exynos5-common/exynos-tmu.h +++ /dev/null @@ -1,132 +0,0 @@ -/* - * Copyright (c) 2012 Samsung Electronics Co., Ltd. - * http://www.samsung.com - * Akshay Saraswat - * - * EXYNOS - Thermal Management Unit - * - * See file CREDITS for list of people who contributed to this - * project. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, - * MA 02111-1307 USA - */ - -#ifndef __EXYNOS_TMU_H -#define __EXYNOS_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 /* EXYNOS_TMU_H */ diff --git a/src/cpu/samsung/exynos5-common/exynos5-common.h b/src/cpu/samsung/exynos5-common/exynos5-common.h deleted file mode 100644 index b2957bfc62..0000000000 --- a/src/cpu/samsung/exynos5-common/exynos5-common.h +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright (C) 2012 Samsung Electronics - * - * Common configuration settings for EXYNOS5 based boards. - * - * See file CREDITS for list of people who contributed to this - * project. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of - * the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, - * MA 02111-1307 USA - */ - -#ifndef __EXYNOS5_CONFIG_H -#define __EXYNOS5_CONFIG_H - -#include /* get chip and board defs */ - -/* TODO(dhendrix): some #defines are commented out here and moved to Kconfig */ - -//#define CONFIG_SYS_SDRAM_BASE 0x40000000 -//#define CONFIG_SYS_TEXT_BASE 0x43e00000 - -/* Power Down Modes */ -#define S5P_CHECK_SLEEP 0x00000BAD -#define S5P_CHECK_DIDLE 0xBAD00000 -#define S5P_CHECK_LPA 0xABAD0000 - -#define CONFIG_SYS_HZ 1000 - -/* We spend about 100us getting from reset to SPL */ -#define CONFIG_SPL_TIME_US 100000 - -#endif /* __EXYNOS5_CONFIG_H */ diff --git a/src/cpu/samsung/exynos5-common/gpio.c b/src/cpu/samsung/exynos5-common/gpio.c deleted file mode 100644 index c9c4c26ced..0000000000 --- a/src/cpu/samsung/exynos5-common/gpio.c +++ /dev/null @@ -1,501 +0,0 @@ -/* - * (C) Copyright 2009 Samsung Electronics - * Minkyu Kang - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of - * the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, - * MA 02111-1307 USA - */ - -/* FIXME(dhendrix): fix this up so it doesn't require a bunch of #ifdefs... */ -#include -#include -//#include -#include -#include -#include -#include -#include /* FIXME: for gpio_decode_number prototype */ - -#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 */ -}; - -#include -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 }, -}; - -#define HAVE_GENERIC_GPIO - -/* This macro gets gpio pin offset from 0..7 */ -#define GPIO_BIT(x) ((x) & 0x7) - -//#ifdef HAVE_GENERIC_GPIO -static struct s5p_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 s5p_gpio_bank *bank; - - bank = (struct s5p_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; -} -//#endif - -/* TODO: Deprecation this interface in favour of asm-generic/gpio.h */ -void s5p_gpio_cfg_pin(struct s5p_gpio_bank *bank, int gpio, int cfg) -{ - unsigned int value; - - value = readl(&bank->con); - value &= ~CON_MASK(gpio); - value |= CON_SFR(gpio, cfg); - writel(value, &bank->con); -} - -void s5p_gpio_direction_output(struct s5p_gpio_bank *bank, int gpio, int en) -{ - unsigned int value; - - s5p_gpio_cfg_pin(bank, gpio, EXYNOS_GPIO_OUTPUT); - - value = readl(&bank->dat); - value &= ~DAT_MASK(gpio); - if (en) - value |= DAT_SET(gpio); - writel(value, &bank->dat); -} - -void s5p_gpio_direction_input(struct s5p_gpio_bank *bank, int gpio) -{ - s5p_gpio_cfg_pin(bank, gpio, EXYNOS_GPIO_INPUT); -} - -void s5p_gpio_set_value(struct s5p_gpio_bank *bank, int gpio, int en) -{ - unsigned int value; - - value = readl(&bank->dat); - value &= ~DAT_MASK(gpio); - if (en) - value |= DAT_SET(gpio); - writel(value, &bank->dat); -} - -unsigned int s5p_gpio_get_value(struct s5p_gpio_bank *bank, int gpio) -{ - unsigned int value; - - value = readl(&bank->dat); - return !!(value & DAT_MASK(gpio)); -} - -void s5p_gpio_set_pull(struct s5p_gpio_bank *bank, int gpio, int mode) -{ - unsigned int value; - - value = readl(&bank->pull); - value &= ~PULL_MASK(gpio); - - switch (mode) { - case EXYNOS_GPIO_PULL_DOWN: - case EXYNOS_GPIO_PULL_UP: - value |= PULL_MODE(gpio, mode); - break; - default: - break; - } - - writel(value, &bank->pull); -} - -void s5p_gpio_set_drv(struct s5p_gpio_bank *bank, int gpio, int mode) -{ - unsigned int value; - - value = readl(&bank->drv); - value &= ~DRV_MASK(gpio); - - switch (mode) { - case EXYNOS_GPIO_DRV_1X: - case EXYNOS_GPIO_DRV_2X: - case EXYNOS_GPIO_DRV_3X: - case EXYNOS_GPIO_DRV_4X: - value |= DRV_SET(gpio, mode); - break; - default: - return; - } - - writel(value, &bank->drv); -} - -void s5p_gpio_set_rate(struct s5p_gpio_bank *bank, int gpio, int mode) -{ - unsigned int value; - - value = readl(&bank->drv); - value &= ~RATE_MASK(gpio); - - switch (mode) { - case EXYNOS_GPIO_DRV_FAST: - case EXYNOS_GPIO_DRV_SLOW: - value |= RATE_SET(gpio); - break; - default: - return; - } - - writel(value, &bank->drv); -} - -/* Common GPIO API - only available on Exynos5 */ -/* FIXME(dhendrix): If this stuff is really only applicable to exynos5, - move it to a more sensible location. */ -#ifdef HAVE_GENERIC_GPIO - -void gpio_cfg_pin(int gpio, int cfg) -{ - unsigned int value; - struct s5p_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 s5p_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 s5p_gpio_bank *bank = gpio_get_bank(gpio); - - value = readl(&bank->pull); - value &= ~PULL_MASK(GPIO_BIT(gpio)); - - switch (mode) { - case EXYNOS_GPIO_PULL_DOWN: - case EXYNOS_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 s5p_gpio_bank *bank = gpio_get_bank(gpio); - - value = readl(&bank->drv); - value &= ~DRV_MASK(GPIO_BIT(gpio)); - - switch (mode) { - case EXYNOS_GPIO_DRV_1X: - case EXYNOS_GPIO_DRV_2X: - case EXYNOS_GPIO_DRV_3X: - case EXYNOS_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 s5p_gpio_bank *bank = gpio_get_bank(gpio); - - value = readl(&bank->drv); - value &= ~RATE_MASK(GPIO_BIT(gpio)); - - switch (mode) { - case EXYNOS_GPIO_DRV_FAST: - case EXYNOS_GPIO_DRV_SLOW: - value |= RATE_SET(GPIO_BIT(gpio)); - break; - default: - return; - } - - writel(value, &bank->drv); -} - -int gpio_request(unsigned gpio, const char *label) -{ - return 0; -} - -int gpio_free(unsigned gpio) -{ - return 0; -} - -int gpio_direction_input(unsigned gpio) -{ - gpio_cfg_pin(gpio, EXYNOS_GPIO_INPUT); - - return 0; -} - -int gpio_direction_output(unsigned gpio, int value) -{ - unsigned int val; - struct s5p_gpio_bank *bank = gpio_get_bank(gpio); - - gpio_cfg_pin(gpio, EXYNOS_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 s5p_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 s5p_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; -} -#else - -static int s5p_gpio_get_pin(unsigned gpio) -{ - return gpio % GPIO_PER_BANK; -} - -/* - * If we have the old-style GPIO numbering setup, use these functions - * which don't necessary provide sequentially increasing GPIO numbers. - */ -static struct s5p_gpio_bank *s5p_gpio_get_bank(unsigned gpio) -{ - int bank = gpio / GPIO_PER_BANK; - bank *= sizeof(struct s5p_gpio_bank); - - return (struct s5p_gpio_bank *) (s5p_gpio_base(gpio) + bank); -} - -int gpio_request(unsigned gpio, const char *label) -{ - return 0; -} - -int gpio_free(unsigned gpio) -{ - return 0; -} - -int gpio_direction_input(unsigned gpio) -{ - s5p_gpio_direction_input(s5p_gpio_get_bank(gpio), - s5p_gpio_get_pin(gpio)); - return 0; -} - -int gpio_direction_output(unsigned gpio, int value) -{ - s5p_gpio_direction_output(s5p_gpio_get_bank(gpio), - s5p_gpio_get_pin(gpio), value); - return 0; -} - -int gpio_get_value(unsigned gpio) -{ - return (int) s5p_gpio_get_value(s5p_gpio_get_bank(gpio), - s5p_gpio_get_pin(gpio)); -} - -int gpio_set_value(unsigned gpio, int value) -{ - s5p_gpio_set_value(s5p_gpio_get_bank(gpio), - s5p_gpio_get_pin(gpio), value); - - return 0; -} - -#endif /* HAVE_GENERIC_GPIO */ - -/* - * 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, EXYNOS_GPIO_PULL_UP); - udelay(GPIO_DELAY_US); - high = gpio_get_value(gpio); - gpio_set_pull(gpio, EXYNOS_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, EXYNOS_GPIO_PULL_UP); - - return value; -} - -int gpio_decode_number(unsigned gpio_list[], int count) -{ - int result = 0; - int multiplier = 1; - int gpio, i, value; - enum mvl3 mvl3; - - for (i = 0; i < count; i++) { - gpio = gpio_list[i]; - - mvl3 = gpio_read_mvl3(gpio); - if (mvl3 == LOGIC_1) - value = 2; - else if (mvl3 == LOGIC_0) - value = 1; - else if (mvl3 == LOGIC_Z) - value = 0; - else - return -1; - - result += value * multiplier; - multiplier *= 3; - } - - return result; -} -#endif /* __BOOT_BLOCK__ */ - -static const char *get_cfg_name(int cfg) -{ - static char name[8]; - - if (cfg == EXYNOS_GPIO_INPUT) - return "input"; - else if (cfg == EXYNOS_GPIO_OUTPUT) - return "output"; - printk(BIOS_INFO, "func %d", cfg); -// sprintf(name, "func %d", cfg); - - return name; -} - -/* - * 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: %s", gpio, get_cfg_name(cfg)); - if (cfg == EXYNOS_GPIO_INPUT || cfg == EXYNOS_GPIO_OUTPUT) - printk(BIOS_INFO, ", value = %d", gpio_get_value(gpio)); - printk(BIOS_INFO, "\n"); - } -} diff --git a/src/cpu/samsung/exynos5-common/gpio.h b/src/cpu/samsung/exynos5-common/gpio.h deleted file mode 100644 index 0e4afc50c8..0000000000 --- a/src/cpu/samsung/exynos5-common/gpio.h +++ /dev/null @@ -1,285 +0,0 @@ -/* - * (C) Copyright 2009-2010 Samsung Electronics - * Minkyu Kang - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of - * the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, - * MA 02111-1307 USA - */ - -#ifndef __ASM_ARCH_COMMON_GPIO_H -#define __ASM_ARCH_COMMON_GPIO_H - -#ifndef __ASSEMBLER__ /* FIXME: not needed (i hope)? */ - -#include /* FIXME: for S5PC110_GPIO_BASE */ - -struct s5p_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]; -}; - -struct s5pc100_gpio { - struct s5p_gpio_bank a0; - struct s5p_gpio_bank a1; - struct s5p_gpio_bank b; - struct s5p_gpio_bank c; - struct s5p_gpio_bank d; - struct s5p_gpio_bank e0; - struct s5p_gpio_bank e1; - struct s5p_gpio_bank f0; - struct s5p_gpio_bank f1; - struct s5p_gpio_bank f2; - struct s5p_gpio_bank f3; - struct s5p_gpio_bank g0; - struct s5p_gpio_bank g1; - struct s5p_gpio_bank g2; - struct s5p_gpio_bank g3; - struct s5p_gpio_bank i; - struct s5p_gpio_bank j0; - struct s5p_gpio_bank j1; - struct s5p_gpio_bank j2; - struct s5p_gpio_bank j3; - struct s5p_gpio_bank j4; - struct s5p_gpio_bank k0; - struct s5p_gpio_bank k1; - struct s5p_gpio_bank k2; - struct s5p_gpio_bank k3; - struct s5p_gpio_bank l0; - struct s5p_gpio_bank l1; - struct s5p_gpio_bank l2; - struct s5p_gpio_bank l3; - struct s5p_gpio_bank l4; - struct s5p_gpio_bank h0; - struct s5p_gpio_bank h1; - struct s5p_gpio_bank h2; - struct s5p_gpio_bank h3; -}; - -struct s5pc110_gpio { - struct s5p_gpio_bank a0; - struct s5p_gpio_bank a1; - struct s5p_gpio_bank b; - struct s5p_gpio_bank c0; - struct s5p_gpio_bank c1; - struct s5p_gpio_bank d0; - struct s5p_gpio_bank d1; - struct s5p_gpio_bank e0; - struct s5p_gpio_bank e1; - struct s5p_gpio_bank f0; - struct s5p_gpio_bank f1; - struct s5p_gpio_bank f2; - struct s5p_gpio_bank f3; - struct s5p_gpio_bank g0; - struct s5p_gpio_bank g1; - struct s5p_gpio_bank g2; - struct s5p_gpio_bank g3; - struct s5p_gpio_bank i; - struct s5p_gpio_bank j0; - struct s5p_gpio_bank j1; - struct s5p_gpio_bank j2; - struct s5p_gpio_bank j3; - struct s5p_gpio_bank j4; - struct s5p_gpio_bank mp0_1; - struct s5p_gpio_bank mp0_2; - struct s5p_gpio_bank mp0_3; - struct s5p_gpio_bank mp0_4; - struct s5p_gpio_bank mp0_5; - struct s5p_gpio_bank mp0_6; - struct s5p_gpio_bank mp0_7; - struct s5p_gpio_bank mp1_0; - struct s5p_gpio_bank mp1_1; - struct s5p_gpio_bank mp1_2; - struct s5p_gpio_bank mp1_3; - struct s5p_gpio_bank mp1_4; - struct s5p_gpio_bank mp1_5; - struct s5p_gpio_bank mp1_6; - struct s5p_gpio_bank mp1_7; - struct s5p_gpio_bank mp1_8; - struct s5p_gpio_bank mp2_0; - struct s5p_gpio_bank mp2_1; - struct s5p_gpio_bank mp2_2; - struct s5p_gpio_bank mp2_3; - struct s5p_gpio_bank mp2_4; - struct s5p_gpio_bank mp2_5; - struct s5p_gpio_bank mp2_6; - struct s5p_gpio_bank mp2_7; - struct s5p_gpio_bank mp2_8; - struct s5p_gpio_bank res1[48]; - struct s5p_gpio_bank h0; - struct s5p_gpio_bank h1; - struct s5p_gpio_bank h2; - struct s5p_gpio_bank h3; -}; - -/* functions */ -void s5p_gpio_cfg_pin(struct s5p_gpio_bank *bank, int gpio, int cfg); -void s5p_gpio_direction_output(struct s5p_gpio_bank *bank, int gpio, int en); -void s5p_gpio_direction_input(struct s5p_gpio_bank *bank, int gpio); -void s5p_gpio_set_value(struct s5p_gpio_bank *bank, int gpio, int en); -unsigned int s5p_gpio_get_value(struct s5p_gpio_bank *bank, int gpio); -void s5p_gpio_set_pull(struct s5p_gpio_bank *bank, int gpio, int mode); -void s5p_gpio_set_drv(struct s5p_gpio_bank *bank, int gpio, int mode); -void s5p_gpio_set_rate(struct s5p_gpio_bank *bank, int gpio, int mode); - -/* GPIO pins per bank */ -#define GPIO_PER_BANK 8 - -static inline unsigned int s5p_gpio_base(int nr) -{ - return S5PC110_GPIO_BASE; -} - -#define s5pc110_gpio_get_nr(bank, pin) \ - ((((((unsigned int)&(((struct s5pc110_gpio *)S5PC110_GPIO_BASE)->bank))\ - - S5PC110_GPIO_BASE) / sizeof(struct s5p_gpio_bank)) \ - * GPIO_PER_BANK) + pin) -#endif - -/* 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 0x2 - -/* 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 - -#if 0 -struct s5p_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]; -}; - -/* functions */ -void s5p_gpio_cfg_pin(struct s5p_gpio_bank *bank, int gpio, int cfg); -void s5p_gpio_direction_output(struct s5p_gpio_bank *bank, int gpio, int en); -void s5p_gpio_direction_input(struct s5p_gpio_bank *bank, int gpio); -void s5p_gpio_set_value(struct s5p_gpio_bank *bank, int gpio, int en); -unsigned int s5p_gpio_get_value(struct s5p_gpio_bank *bank, int gpio); -void s5p_gpio_set_pull(struct s5p_gpio_bank *bank, int gpio, int mode); -void s5p_gpio_set_drv(struct s5p_gpio_bank *bank, int gpio, int mode); -void s5p_gpio_set_rate(struct s5p_gpio_bank *bank, int gpio, int mode); -#endif - -/* GPIO pins per bank */ -#define GPIO_PER_BANK 8 - -/* Pin configurations */ -#define EXYNOS_GPIO_INPUT 0x0 -#define EXYNOS_GPIO_OUTPUT 0x1 -#define EXYNOS_GPIO_IRQ 0xf -#define EXYNOS_GPIO_FUNC(x) (x) - -/* Pull mode */ -#define EXYNOS_GPIO_PULL_NONE 0x0 -#define EXYNOS_GPIO_PULL_DOWN 0x1 -#define EXYNOS_GPIO_PULL_UP 0x3 - -/* Drive Strength level */ -#define EXYNOS_GPIO_DRV_1X 0x0 -#define EXYNOS_GPIO_DRV_3X 0x1 -#define EXYNOS_GPIO_DRV_2X 0x2 -#define EXYNOS_GPIO_DRV_4X 0x3 -#define EXYNOS_GPIO_DRV_FAST 0x0 -#define EXYNOS_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, -}; - -#endif diff --git a/src/cpu/samsung/exynos5-common/i2c.c b/src/cpu/samsung/exynos5-common/i2c.c deleted file mode 100644 index 30fabe1659..0000000000 --- a/src/cpu/samsung/exynos5-common/i2c.c +++ /dev/null @@ -1,414 +0,0 @@ -/* - * (C) Copyright 2002 - * David Mueller, ELSOFT AG, d.mueller@elsoft.ch - * - * See file CREDITS for list of people who contributed to this - * project. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of - * the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, - * MA 02111-1307 USA - */ - -/* This code should work for both the S3C2400 and the S3C2410 - * as they seem to have the same I2C controller inside. - * The different address mapping is handled by the s3c24xx.h files below. - */ - -#include -#include -#include -#include -#include "cpu/samsung/exynos5-common/clk.h" -#include "cpu/samsung/exynos5-common/i2c.h" -#include "cpu/samsung/exynos5250/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[] = { - /* FIXME: exynos5250-specific? */ - { - .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; -} diff --git a/src/cpu/samsung/exynos5-common/i2c.h b/src/cpu/samsung/exynos5-common/i2c.h deleted file mode 100644 index 0bfee340e1..0000000000 --- a/src/cpu/samsung/exynos5-common/i2c.h +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright (C) 2012 Samsung Electronics - * - * See file CREDITS for list of people who contributed to this - * project. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of - * the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, - * MA 02111-1307 USA - */ - -#ifndef _S3C24X0_I2C_H -#define _S3C24X0_I2C_H - -/* FIXME: gross hack */ -#include "cpu/samsung/exynos5250/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 /* _S3C24X0_I2C_H */ diff --git a/src/cpu/samsung/exynos5-common/power.h b/src/cpu/samsung/exynos5-common/power.h deleted file mode 100644 index ff98123d6d..0000000000 --- a/src/cpu/samsung/exynos5-common/power.h +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright (c) 2009 Samsung Electronics - * Kyungmin Park - * Minkyu Kang - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of - * the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, - * MA 02111-1307 USA - * - */ - -#ifndef __ASM_ARM_ARCH_POWER_H_ -#define __ASM_ARM_ARCH_POWER_H_ - -/* - * Power control - */ -#define S5PC100_OTHERS 0xE0108200 -#define S5PC100_RST_STAT 0xE0108300 -#define S5PC100_SLEEP_WAKEUP (1 << 3) -#define S5PC100_WAKEUP_STAT 0xE0108304 -#define S5PC100_INFORM0 0xE0108400 - -#define S5PC110_RST_STAT 0xE010A000 -#define S5PC110_SLEEP_WAKEUP (1 << 3) -#define S5PC110_WAKEUP_STAT 0xE010C200 -#define S5PC110_OTHERS 0xE010E000 -#define S5PC110_USB_PHY_CON 0xE010E80C -#define S5PC110_INFORM0 0xE010F000 - -/* Enable HW thermal trip with PS_HOLD_CONTROL register ENABLE_HW_TRIP bit */ -void power_enable_hw_thermal_trip(void); - -#endif diff --git a/src/cpu/samsung/exynos5-common/pwm.c b/src/cpu/samsung/exynos5-common/pwm.c deleted file mode 100644 index 0fc571b220..0000000000 --- a/src/cpu/samsung/exynos5-common/pwm.c +++ /dev/null @@ -1,199 +0,0 @@ -/* - * Copyright (C) 2011 Samsung Electronics - * - * Donghwa Lee - * - * See file CREDITS for list of people who contributed to this - * project. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of - * the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, - * MA 02111-1307 USA - */ - -#include -#include -#include -#include -#include -#include - -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; -// return -ERANGE; - - if (duty_ns > period_ns) - return -1; -// return -EINVAL; - - 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; -} diff --git a/src/cpu/samsung/exynos5-common/pwm.h b/src/cpu/samsung/exynos5-common/pwm.h deleted file mode 100644 index d7aa76fd15..0000000000 --- a/src/cpu/samsung/exynos5-common/pwm.h +++ /dev/null @@ -1,74 +0,0 @@ -/* - * Copyright (C) 2009 Samsung Electronics - * Kyungmin Park - * Minkyu Kang - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of - * the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, - * MA 02111-1307 USA - */ - -#ifndef __ASM_ARM_ARCH_COMMON_PWM_H_ -#define __ASM_ARM_ARCH_COMMON_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) - -#ifndef __ASSEMBLER__ -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 /* __ASSEMBLER__ */ - -#endif diff --git a/src/cpu/samsung/exynos5-common/reset.c b/src/cpu/samsung/exynos5-common/reset.c deleted file mode 100644 index 6cbc1d88e5..0000000000 --- a/src/cpu/samsung/exynos5-common/reset.c +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Copyright (c) 2010 Samsung Electronics. - * Minkyu Kang - * - * See file CREDITS for list of people who contributed to this - * project. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of - * the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, - * MA 02111-1307 USA - */ - -#include -#include - -void soft_reset(void) -{ - writel(0x1, samsung_get_base_swreset()); -} diff --git a/src/cpu/samsung/exynos5-common/s5p-dp-core.h b/src/cpu/samsung/exynos5-common/s5p-dp-core.h deleted file mode 100644 index 4df848d0ea..0000000000 --- a/src/cpu/samsung/exynos5-common/s5p-dp-core.h +++ /dev/null @@ -1,257 +0,0 @@ -/* - * Header file for Samsung DP (Display Port) interface driver. - * - * Copyright 2013 Google Inc. - * Copyright (C) 2012 Samsung Electronics Co., Ltd. - * Author: Jingoo Han - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. - */ - -#ifndef _S5P_DP_CORE_H -#define _S5P_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 /* _S5P_DP_CORE_H */ diff --git a/src/cpu/samsung/exynos5-common/s5p-dp-reg.c b/src/cpu/samsung/exynos5-common/s5p-dp-reg.c deleted file mode 100644 index cce8c6d212..0000000000 --- a/src/cpu/samsung/exynos5-common/s5p-dp-reg.c +++ /dev/null @@ -1,486 +0,0 @@ -/* - * Samsung DP (Display port) register interface driver. - * - * Copyright (C) 2012 Samsung Electronics Co., Ltd. - * Author: Jingoo Han - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. - */ - -#include -#include -#include -#include -#include -#include -#include "cpu/samsung/exynos5250/fimd.h" -#include "s5p-dp-core.h" - -#include - -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); -} diff --git a/src/cpu/samsung/exynos5-common/spi.c b/src/cpu/samsung/exynos5-common/spi.c deleted file mode 100644 index 33f4d99fd2..0000000000 --- a/src/cpu/samsung/exynos5-common/spi.c +++ /dev/null @@ -1,227 +0,0 @@ -/* - * Copyright (C) 2011 Samsung Electronics - * Copyright (C) 2013 The Chromium OS Authors. All rights reserved. - * - * See file CREDITS for list of people who contributed to this - * project. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of - * the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, - * MA 02111-1307 USA - */ - -#include - -#include -#include - -#include -#include - -#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); -} diff --git a/src/cpu/samsung/exynos5-common/spi.h b/src/cpu/samsung/exynos5-common/spi.h deleted file mode 100644 index 156817c35b..0000000000 --- a/src/cpu/samsung/exynos5-common/spi.h +++ /dev/null @@ -1,102 +0,0 @@ -/* - * (C) Copyright 2012 SAMSUNG Electronics - * Padmavathi Venna - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifndef __ASM_ARCH_EXYNOS_COMMON_SPI_H_ -#define __ASM_ARCH_EXYNOS_COMMON_SPI_H_ - -#ifndef __ASSEMBLER__ - -// This driver serves as a CBFS media source. -#include - -/* 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 */ -int initialize_exynos_spi_cbfs_media(struct cbfs_media *media, - void *buffer_address, - size_t buffer_size); - -#endif /* __ASSEMBLER__ */ -#endif diff --git a/src/cpu/samsung/exynos5-common/sromc.c b/src/cpu/samsung/exynos5-common/sromc.c deleted file mode 100644 index 7bc93e7862..0000000000 --- a/src/cpu/samsung/exynos5-common/sromc.c +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright (C) 2010 Samsung Electronics - * Naveen Krishna Ch - * - * See file CREDITS for list of people who contributed to this - * project. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of - * the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, - * MA 02111-1307 USA - */ - -#include -#include -#include - -/* - * s5p_config_sromc() - select the proper SROMC Bank and configure the - * band width control and bank control registers - * srom_bank - SROM - * srom_bw_conf - SMC Band witdh reg configuration value - * srom_bc_conf - SMC Bank Control reg configuration value - */ -void s5p_config_sromc(u32 srom_bank, u32 srom_bw_conf, u32 srom_bc_conf) -{ - u32 tmp; - struct s5p_sromc *srom = - samsung_get_base_sromc(); - - /* Configure SMC_BW register to handle proper SROMC bank */ - tmp = srom->bw; - tmp &= ~(0xF << (srom_bank * 4)); - tmp |= srom_bw_conf; - srom->bw = tmp; - - /* Configure SMC_BC register */ - srom->bc[srom_bank] = srom_bc_conf; -} diff --git a/src/cpu/samsung/exynos5-common/sromc.h b/src/cpu/samsung/exynos5-common/sromc.h deleted file mode 100644 index d4fdae90e6..0000000000 --- a/src/cpu/samsung/exynos5-common/sromc.h +++ /dev/null @@ -1,69 +0,0 @@ -/* - * (C) Copyright 2010 Samsung Electronics - * Naveen Krishna 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; either version 2 of - * the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, - * MA 02111-1307 USA - * - * Note: This file contains the register description for SROMC - * - */ - -#ifndef __ASM_ARCH_COMMON_SROMC_H_ -#define __ASM_ARCH_COMMON_SROMC_H_ - -#define SROMC_DATA16_WIDTH(x) (1<<((x*4)+0)) -#define SROMC_BYTE_ADDR_MODE(x) (1<<((x*4)+1)) /* 0-> Half-word base address*/ - /* 1-> Byte base address*/ -#define SROMC_WAIT_ENABLE(x) (1<<((x*4)+2)) -#define SROMC_BYTE_ENABLE(x) (1<<((x*4)+3)) - -#define SROMC_BC_TACS(x) (x << 28) /* address set-up */ -#define SROMC_BC_TCOS(x) (x << 24) /* chip selection set-up */ -#define SROMC_BC_TACC(x) (x << 16) /* access cycle */ -#define SROMC_BC_TCOH(x) (x << 12) /* chip selection hold */ -#define SROMC_BC_TAH(x) (x << 8) /* address holding time */ -#define SROMC_BC_TACP(x) (x << 4) /* page mode access cycle */ -#define SROMC_BC_PMC(x) (x << 0) /* normal(1data)page mode configuration */ - -#ifndef __ASSEMBLER__ -struct s5p_sromc { - unsigned int bw; - unsigned int bc[4]; -}; -#endif /* __ASSEMBLER__ */ - -/* Configure the Band Width and Bank Control Regs for required SROMC Bank */ -void s5p_config_sromc(u32 srom_bank, u32 srom_bw_conf, u32 srom_bc_conf); - -enum { - FDT_SROM_PMC, - FDT_SROM_TACP, - FDT_SROM_TAH, - FDT_SROM_TCOH, - FDT_SROM_TACC, - FDT_SROM_TCOS, - FDT_SROM_TACS, - - FDT_SROM_TIMING_COUNT, -}; - -struct fdt_sromc { - u8 bank; /* srom bank number */ - u8 width; /* bus width in bytes */ - unsigned int timing[FDT_SROM_TIMING_COUNT]; /* timing parameters */ -}; - -#endif /* __ASM_ARCH_COMMON_SROMC_H_ */ diff --git a/src/cpu/samsung/exynos5-common/timer.c b/src/cpu/samsung/exynos5-common/timer.c deleted file mode 100644 index c8e419a57c..0000000000 --- a/src/cpu/samsung/exynos5-common/timer.c +++ /dev/null @@ -1,164 +0,0 @@ -/* - * Copyright (C) 2009 Samsung Electronics - * Heungjun Kim - * Inki Dae - * Minkyu Kang - * - * See file CREDITS for list of people who contributed to this - * project. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of - * the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, - * MA 02111-1307 USA - */ - -#include -#include -#include -#include -#include -#include -#include -#include - -//#include - -//DECLARE_GLOBAL_DATA_PTR; -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); -} - -int 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 */ - //gd->timer_reset_value = 0; - timer_reset_value = 0; - - /* Use this as the last timer value we saw */ - //gd->lastinc = timer_get_us_down(); - lastinc = timer_get_us_down(); - } - - return 0; -} - -/* - * 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. - */ -#if 0 - gd->timer_reset_value += gd->lastinc - now; - gd->lastinc = now; - - /* Divide by 1000 to convert from us to ms */ - return gd->timer_reset_value / 1000 - base; -#endif - timer_reset_value += lastinc - now; - lastinc = now; - - /* Divide by 1000 to convert from us to ms */ - return timer_reset_value / 1000 - base; -} - -unsigned long timer_get_us(void) -{ - struct s5p_timer *const timer = s5p_get_base_timer(); - unsigned long now_downward_us = readl(&timer->tcnto4); - - /* - * Note that this timer counts downward. The pre-SPL process (BL1) - * takes about 100ms, so add this in here. - */ - return CONFIG_SPL_TIME_US - now_downward_us; -} - -/* delay x useconds */ -void udelay(unsigned long 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%08lx 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); -} - -/* - * This function is derived from PowerPC code (read timebase as long long). - * On ARM it just returns the timer value. - */ -unsigned long long get_ticks(void) -{ - return get_timer(0); -} - -/* - * This function is derived from PowerPC code (timebase clock frequency). - * On ARM it returns the number of timer ticks per second. - */ -unsigned long get_tbclk(void) -{ - return CONFIG_SYS_HZ; -} - -unsigned long timer_get_boot_us(void) -{ - return timer_get_us(); -} diff --git a/src/cpu/samsung/exynos5-common/uart.h b/src/cpu/samsung/exynos5-common/uart.h deleted file mode 100644 index 350e224b86..0000000000 --- a/src/cpu/samsung/exynos5-common/uart.h +++ /dev/null @@ -1,55 +0,0 @@ -/* - * (C) Copyright 2009 Samsung Electronics - * Minkyu Kang - * Heungjun Kim - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of - * the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, - * MA 02111-1307 USA - * - */ - -#ifndef __EXYNOS_COMMON_UART_H_ -#define __EXYNOS_COMMON_UART_H_ - -/* 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]; -}; - -static inline int s5p_uart_divslot(void) -{ - return 0; -} - -#endif diff --git a/src/cpu/samsung/exynos5-common/watchdog.h b/src/cpu/samsung/exynos5-common/watchdog.h deleted file mode 100644 index 5b3b651ffa..0000000000 --- a/src/cpu/samsung/exynos5-common/watchdog.h +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Copyright (C) 2011 Samsung Electronics - * Heungjun Kim - * - * See file CREDITS for list of people who contributed to this - * project. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of - * the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, - * MA 02111-1307 USA - */ - -#ifndef __ASM_ARM_ARCH_COMMON_WATCHDOG_H_ -#define __ASM_ARM_ARCH_COMMON_WATCHDOG_H_ - -#define WTCON_RESET_OFFSET 0 -#define WTCON_INTEN_OFFSET 2 -#define WTCON_CLKSEL_OFFSET 3 -#define WTCON_EN_OFFSET 5 -#define WTCON_PRE_OFFSET 8 - -#define WTCON_CLK_16 0x0 -#define WTCON_CLK_32 0x1 -#define WTCON_CLK_64 0x2 -#define WTCON_CLK_128 0x3 - -#define WTCON_CLK(x) ((x & 0x3) << WTCON_CLKSEL_OFFSET) -#define WTCON_PRESCALER(x) ((x) << WTCON_PRE_OFFSET) -#define WTCON_EN (0x1 << WTCON_EN_OFFSET) -#define WTCON_RESET (0x1 << WTCON_RESET_OFFSET) -#define WTCON_INT (0x1 << WTCON_INTEN_OFFSET) - -#ifndef __ASSEMBLER__ -struct s5p_watchdog { - unsigned int wtcon; - unsigned int wtdat; - unsigned int wtcnt; - unsigned int wtclrint; -}; - -/* functions */ -void wdt_stop(void); -void wdt_start(unsigned int timeout); -#endif /* __ASSEMBLER__ */ - -#endif diff --git a/src/cpu/samsung/exynos5-common/wdt.c b/src/cpu/samsung/exynos5-common/wdt.c deleted file mode 100644 index dbeefec49a..0000000000 --- a/src/cpu/samsung/exynos5-common/wdt.c +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Copyright (C) 2012 Samsung Electronics - * Minkyu Kang - * - * See file CREDITS for list of people who contributed to this - * project. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of - * the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, - * MA 02111-1307 USA - */ - -#include -#include -#include - -#define PRESCALER_VAL 255 - -void wdt_stop(void) -{ - struct s5p_watchdog *wdt = - samsung_get_base_watchdog(); - unsigned int wtcon; - - wtcon = readl(&wdt->wtcon); - wtcon &= ~(WTCON_EN | WTCON_INT | WTCON_RESET); - - writel(wtcon, &wdt->wtcon); -} - -void wdt_start(unsigned int timeout) -{ - struct s5p_watchdog *wdt = - samsung_get_base_watchdog(); - unsigned int wtcon; - - wdt_stop(); - - wtcon = readl(&wdt->wtcon); - wtcon |= (WTCON_EN | WTCON_CLK(WTCON_CLK_128)); - wtcon &= ~WTCON_INT; - wtcon |= WTCON_RESET; - wtcon |= WTCON_PRESCALER(PRESCALER_VAL); - - writel(timeout, &wdt->wtdat); - writel(timeout, &wdt->wtcnt); - writel(wtcon, &wdt->wtcon); -} diff --git a/src/cpu/samsung/exynos5250/Makefile.inc b/src/cpu/samsung/exynos5250/Makefile.inc index 6449714a51..d89bc95ce2 100644 --- a/src/cpu/samsung/exynos5250/Makefile.inc +++ b/src/cpu/samsung/exynos5250/Makefile.inc @@ -3,6 +3,7 @@ # image outside of CBFS INTERMEDIATE += exynos5250_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 @@ -11,7 +12,11 @@ bootblock-$(CONFIG_EARLY_CONSOLE) += monotonic_timer.c bootblock-$(CONFIG_EARLY_CONSOLE) += soc.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 (exynos5-common) and uart. @@ -23,7 +28,14 @@ romstage-y += monotonic_timer.c romstage-$(CONFIG_EARLY_CONSOLE) += soc.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 +#romstage-y += sromc.c +ramstage-y += spi.c #ramstage-y += tzpc_init.c ramstage-y += clock.c ramstage-y += clock_init.c @@ -35,8 +47,15 @@ ramstage-y += cpu.c ramstage-y += exynos5250-tmu.c ramstage-y += mct.c ramstage-y += monotonic_timer.c - #ramstage-$(CONFIG_SATA_AHCI) += sata.c +ramstage-y += cpu_info.c +ramstage-y += pwm.c # needed by timer.c +ramstage-y += timer.c +ramstage-y += gpio.c +ramstage-y += i2c.c +ramstage-y += s5p-dp-reg.c +ramstage-y += exynos-fb.c +ramstage-y += exynos-tmu.c exynos5250_add_bl1: $(obj)/coreboot.pre printf " DD Adding Samsung Exynos5250 BL1\n" diff --git a/src/cpu/samsung/exynos5250/adc.h b/src/cpu/samsung/exynos5250/adc.h new file mode 100644 index 0000000000..64f4813495 --- /dev/null +++ b/src/cpu/samsung/exynos5250/adc.h @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2010 Samsung Electronics + * Minkyu Kang + * MyungJoo Ham + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#ifndef __ASM_ARM_ARCH_COMMON_ADC_H_ +#define __ASM_ARM_ARCH_COMMON_ADC_H_ + +#ifndef __ASSEMBLER__ +struct s5p_adc { + unsigned int adccon; + unsigned int adctsc; + unsigned int adcdly; + unsigned int adcdat0; + unsigned int adcdat1; + unsigned int adcupdn; + unsigned int adcclrint; + unsigned int adcmux; + unsigned int adcclrintpndnup; +}; +#endif + +#endif /* __ASM_ARM_ARCH_COMMON_ADC_H_ */ diff --git a/src/cpu/samsung/exynos5250/clk.h b/src/cpu/samsung/exynos5250/clk.h index 828e7d8832..24e8e7066c 100644 --- a/src/cpu/samsung/exynos5250/clk.h +++ b/src/cpu/samsung/exynos5250/clk.h @@ -22,7 +22,50 @@ #ifndef __EXYNOS5_CLK_H__ #define __EXYNOS5_CLK_H__ -#include +#include +#include + +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 diff --git a/src/cpu/samsung/exynos5250/clock.c b/src/cpu/samsung/exynos5250/clock.c index 3622e28351..de41346faa 100644 --- a/src/cpu/samsung/exynos5250/clock.c +++ b/src/cpu/samsung/exynos5250/clock.c @@ -29,7 +29,6 @@ #include #include #include -#include /* input clock of PLL: SMDK5250 has 24MHz input clock */ #define CONFIG_SYS_CLK_FREQ 24000000 diff --git a/src/cpu/samsung/exynos5250/clock.h b/src/cpu/samsung/exynos5250/clock.h new file mode 100644 index 0000000000..c0cd896b22 --- /dev/null +++ b/src/cpu/samsung/exynos5250/clock.h @@ -0,0 +1,94 @@ +/* + * (C) Copyright 2009 Samsung Electronics + * Minkyu Kang + * Heungjun Kim + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + */ + +#ifndef __ASM_ARM_ARCH_CLOCK_H_ +#define __ASM_ARM_ARCH_CLOCK_H_ + +#ifndef __ASSEMBLER__ +struct s5pc100_clock { + unsigned int apll_lock; + unsigned int mpll_lock; + unsigned int epll_lock; + unsigned int hpll_lock; + unsigned char res1[0xf0]; + unsigned int apll_con; + unsigned int mpll_con; + unsigned int epll_con; + unsigned int hpll_con; + unsigned char res2[0xf0]; + unsigned int src0; + unsigned int src1; + unsigned int src2; + unsigned int src3; + unsigned char res3[0xf0]; + unsigned int div0; + unsigned int div1; + unsigned int div2; + unsigned int div3; + unsigned int div4; + unsigned char res4[0x1ec]; + unsigned int gate_d00; + unsigned int gate_d01; + unsigned int gate_d02; + unsigned char res5[0x54]; + unsigned int gate_sclk0; + unsigned int gate_sclk1; +}; + +struct s5pc110_clock { + unsigned int apll_lock; + unsigned char res1[0x4]; + unsigned int mpll_lock; + unsigned char res2[0x4]; + unsigned int epll_lock; + unsigned char res3[0xc]; + unsigned int vpll_lock; + unsigned char res4[0xdc]; + unsigned int apll_con; + unsigned char res5[0x4]; + unsigned int mpll_con; + unsigned char res6[0x4]; + unsigned int epll_con; + unsigned char res7[0xc]; + unsigned int vpll_con; + unsigned char res8[0xdc]; + unsigned int src0; + unsigned int src1; + unsigned int src2; + unsigned int src3; + unsigned char res9[0xf0]; + unsigned int div0; + unsigned int div1; + unsigned int div2; + unsigned int div3; + unsigned int div4; + unsigned char res10[0x1ec]; + unsigned int gate_d00; + unsigned int gate_d01; + unsigned int gate_d02; + unsigned char res11[0x54]; + unsigned int gate_sclk0; + unsigned int gate_sclk1; +}; +#endif + +#endif diff --git a/src/cpu/samsung/exynos5250/clock_init.c b/src/cpu/samsung/exynos5250/clock_init.c index 0989b88bb5..42ff9adbd3 100644 --- a/src/cpu/samsung/exynos5250/clock_init.c +++ b/src/cpu/samsung/exynos5250/clock_init.c @@ -34,7 +34,6 @@ #include #include #include -#include #include "setup.h" diff --git a/src/cpu/samsung/exynos5250/cpu.c b/src/cpu/samsung/exynos5250/cpu.c index c49dec453d..2acebbb6e9 100644 --- a/src/cpu/samsung/exynos5250/cpu.c +++ b/src/cpu/samsung/exynos5250/cpu.c @@ -7,8 +7,8 @@ #include #include #include -#include -#include +#include +#include #include "chip.h" #include "cpu.h" diff --git a/src/cpu/samsung/exynos5250/cpu.h b/src/cpu/samsung/exynos5250/cpu.h index cff966ee98..1f94d8f986 100644 --- a/src/cpu/samsung/exynos5250/cpu.h +++ b/src/cpu/samsung/exynos5250/cpu.h @@ -22,7 +22,105 @@ #ifndef _EXYNOS5250_CPU_H #define _EXYNOS5250_CPU_H -#include +#define S5PC1XX_ADDR_BASE 0xE0000000 + +/* S5PC100 */ +#define S5PC100_PRO_ID 0xE0000000 +#define S5PC100_CLOCK_BASE 0xE0100000 +#define S5PC100_GPIO_BASE 0xE0300000 +#define S5PC100_VIC0_BASE 0xE4000000 +#define S5PC100_VIC1_BASE 0xE4100000 +#define S5PC100_VIC2_BASE 0xE4200000 +#define S5PC100_DMC_BASE 0xE6000000 +#define S5PC100_SROMC_BASE 0xE7000000 +#define S5PC100_ONENAND_BASE 0xE7100000 +#define S5PC100_PWMTIMER_BASE 0xEA000000 +#define S5PC100_WATCHDOG_BASE 0xEA200000 +#define S5PC100_UART_BASE 0xEC000000 +#define S5PC100_MMC_BASE 0xED800000 + +/* S5PC110 */ +#define S5PC110_PRO_ID 0xE0000000 +#define S5PC110_CLOCK_BASE 0xE0100000 +#define S5PC110_GPIO_BASE 0xE0200000 +#define S5PC110_PWMTIMER_BASE 0xE2500000 +#define S5PC110_WATCHDOG_BASE 0xE2700000 +#define S5PC110_UART_BASE 0xE2900000 +#define S5PC110_SROMC_BASE 0xE8000000 +#define S5PC110_MMC_BASE 0xEB000000 +#define S5PC110_DMC0_BASE 0xF0000000 +#define S5PC110_DMC1_BASE 0xF1400000 +#define S5PC110_VIC0_BASE 0xF2000000 +#define S5PC110_VIC1_BASE 0xF2100000 +#define S5PC110_VIC2_BASE 0xF2200000 +#define S5PC110_VIC3_BASE 0xF2300000 +#define S5PC110_OTG_BASE 0xEC000000 +#define S5PC110_PHY_BASE 0xEC100000 +#define S5PC110_USB_PHY_CONTROL 0xE010E80C + +#include + +#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 + +enum boot_mode { + /* + * Assign the OM pin values for respective boot modes. + * Exynos4 does not support spi boot and the mmc boot OM + * pin values are the same across Exynos4 and Exynos5. + */ + BOOT_MODE_MMC = 4, + BOOT_MODE_SERIAL = 20, + /* Boot based on Operating Mode pin settings */ + BOOT_MODE_OM = 32, + BOOT_MODE_USB, /* Boot using USB download */ +}; + +/** + * Get the boot device containing BL1, BL2 (SPL) and U-boot + * + * @return boot device + */ +enum boot_mode exynos_get_boot_device(void); + +/** + * Check if a wakeup is permitted. + * + * On some boards we need to look at a special GPIO to ensure that the wakeup + * from sleep was valid. If the wakeup is not valid we need to go through a + * full reset. + * + * The default implementation of this function allows all wakeups. + * + * @return 1 if wakeup is permitted; 0 otherwise + */ +int board_wakeup_permitted(void); + +/** + * Init subsystems according to the reset status + * + * @return 0 for a normal boot, non-zero for a resume + */ +int lowlevel_init_subsystems(void); + +int arch_cpu_init(void); /* EXYNOS5 */ #define EXYNOS5_GPIO_PART6_BASE 0x03860000 /* Z<6:0> */ diff --git a/src/cpu/samsung/exynos5250/cpu_info.c b/src/cpu/samsung/exynos5250/cpu_info.c new file mode 100644 index 0000000000..498ed85a13 --- /dev/null +++ b/src/cpu/samsung/exynos5250/cpu_info.c @@ -0,0 +1,64 @@ +/* + * Copyright (C) 2009 Samsung Electronics + * Minkyu Kang + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#include +#include +#include + +#include +#include +#include +#include + +/* FIXME(dhendrix): consolidate samsung ID code/#defines to a common location */ +#include /* cpu_info_init() prototype */ + +static unsigned int s5p_cpu_id; +static unsigned int s5p_cpu_rev; + +static void s5p_set_cpu_id(void) +{ + s5p_cpu_id = readl((void *)EXYNOS_PRO_ID); + s5p_cpu_id = (0xC000 | ((s5p_cpu_id & 0x00FFF000) >> 12)); + + /* + * 0xC200: EXYNOS4210 EVT0 + * 0xC210: EXYNOS4210 EVT1 + */ + if (s5p_cpu_id == 0xC200) { + s5p_cpu_id |= 0x10; + s5p_cpu_rev = 0; + } else if (s5p_cpu_id == 0xC210) { + s5p_cpu_rev = 1; + } +} + +int arch_cpu_init(void) +{ + s5p_set_cpu_id(); + + printk(BIOS_INFO, "CPU: S5P%X @ %ldMHz\n", + s5p_cpu_id, get_arm_clk() / (1024*1024)); + + return 0; +} diff --git a/src/cpu/samsung/exynos5250/dmc_init_ddr3.c b/src/cpu/samsung/exynos5250/dmc_init_ddr3.c index 132471de74..3dc9b47dd1 100644 --- a/src/cpu/samsung/exynos5250/dmc_init_ddr3.c +++ b/src/cpu/samsung/exynos5250/dmc_init_ddr3.c @@ -26,9 +26,8 @@ #include #include #include -//#include "clock.h" /* FIXME(dhendrix): untangle clock/clk ... */ -#include +#include #include "clk.h" #include "cpu.h" #include "dmc.h" diff --git a/src/cpu/samsung/exynos5250/exynos-fb.c b/src/cpu/samsung/exynos5250/exynos-fb.c new file mode 100644 index 0000000000..5b67120288 --- /dev/null +++ b/src/cpu/samsung/exynos5250/exynos-fb.c @@ -0,0 +1,606 @@ +/* + * LCD driver for Exynos + * + * Copyright 2013 Google Inc. + * Copyright (C) 2012 Samsung Electronics + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "device/i2c.h" +#include "cpu/samsung/exynos5250/i2c.h" +#include "cpu/samsung/exynos5250/dsim.h" +#include "cpu/samsung/exynos5250/fimd.h" + +#include "cpu/samsung/exynos5250/s5p-dp.h" +#include "s5p-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; + + +#ifdef CONFIG_EXYNOS_DISPLAYPORT +static struct s5p_dp_device dp_device; + +#endif + +/* 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<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); +} + +void exynos_fimd_disable(void); +void exynos_fimd_disable(void) +{ + struct exynos5_fimd *fimd = samsung_get_base_fimd(); + + writel(0, &fimd->wincon0); + clrbits_le32(&fimd->shadowcon, CHANNEL0_EN); +} + +/* + * 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; +} diff --git a/src/cpu/samsung/exynos5250/exynos-tmu.c b/src/cpu/samsung/exynos5250/exynos-tmu.c new file mode 100644 index 0000000000..2bd959c9ee --- /dev/null +++ b/src/cpu/samsung/exynos5250/exynos-tmu.c @@ -0,0 +1,195 @@ +/* + * Copyright (c) 2012 Samsung Electronics Co., Ltd. + * http://www.samsung.com + * Akshay Saraswat + * Copyright (c) 2013 Google Inc. + * + * EXYNOS - Thermal Management Unit + * + * This file was originally imported from Das U-Boot and then re-factored + * for coreboot. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#include +#include +#include + +#include + +#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) + +/* + * 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; +} diff --git a/src/cpu/samsung/exynos5250/exynos-tmu.h b/src/cpu/samsung/exynos5250/exynos-tmu.h new file mode 100644 index 0000000000..40eda5626e --- /dev/null +++ b/src/cpu/samsung/exynos5250/exynos-tmu.h @@ -0,0 +1,132 @@ +/* + * Copyright (c) 2012 Samsung Electronics Co., Ltd. + * http://www.samsung.com + * Akshay Saraswat + * + * EXYNOS - Thermal Management Unit + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#ifndef __EXYNOS_TMU_H +#define __EXYNOS_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 /* EXYNOS_TMU_H */ diff --git a/src/cpu/samsung/exynos5250/exynos5-common.h b/src/cpu/samsung/exynos5250/exynos5-common.h new file mode 100644 index 0000000000..b2957bfc62 --- /dev/null +++ b/src/cpu/samsung/exynos5250/exynos5-common.h @@ -0,0 +1,45 @@ +/* + * Copyright (C) 2012 Samsung Electronics + * + * Common configuration settings for EXYNOS5 based boards. + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#ifndef __EXYNOS5_CONFIG_H +#define __EXYNOS5_CONFIG_H + +#include /* get chip and board defs */ + +/* TODO(dhendrix): some #defines are commented out here and moved to Kconfig */ + +//#define CONFIG_SYS_SDRAM_BASE 0x40000000 +//#define CONFIG_SYS_TEXT_BASE 0x43e00000 + +/* Power Down Modes */ +#define S5P_CHECK_SLEEP 0x00000BAD +#define S5P_CHECK_DIDLE 0xBAD00000 +#define S5P_CHECK_LPA 0xABAD0000 + +#define CONFIG_SYS_HZ 1000 + +/* We spend about 100us getting from reset to SPL */ +#define CONFIG_SPL_TIME_US 100000 + +#endif /* __EXYNOS5_CONFIG_H */ diff --git a/src/cpu/samsung/exynos5250/exynos5250-tmu.c b/src/cpu/samsung/exynos5250/exynos5250-tmu.c index 7d8397c568..248968b9b4 100644 --- a/src/cpu/samsung/exynos5250/exynos5250-tmu.c +++ b/src/cpu/samsung/exynos5250/exynos5250-tmu.c @@ -22,7 +22,7 @@ * This file contains Exynos5250-specific TMU information. */ -#include +#include #include struct tmu_info exynos5250_tmu_info = { diff --git a/src/cpu/samsung/exynos5250/gpio.c b/src/cpu/samsung/exynos5250/gpio.c new file mode 100644 index 0000000000..853fa6fe71 --- /dev/null +++ b/src/cpu/samsung/exynos5250/gpio.c @@ -0,0 +1,500 @@ +/* + * (C) Copyright 2009 Samsung Electronics + * Minkyu Kang + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +/* FIXME(dhendrix): fix this up so it doesn't require a bunch of #ifdefs... */ +#include +#include +//#include +#include +#include +#include +#include /* FIXME: for gpio_decode_number prototype */ + +#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 */ +}; + +#include +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 }, +}; + +#define HAVE_GENERIC_GPIO + +/* This macro gets gpio pin offset from 0..7 */ +#define GPIO_BIT(x) ((x) & 0x7) + +//#ifdef HAVE_GENERIC_GPIO +static struct s5p_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 s5p_gpio_bank *bank; + + bank = (struct s5p_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; +} +//#endif + +/* TODO: Deprecation this interface in favour of asm-generic/gpio.h */ +void s5p_gpio_cfg_pin(struct s5p_gpio_bank *bank, int gpio, int cfg) +{ + unsigned int value; + + value = readl(&bank->con); + value &= ~CON_MASK(gpio); + value |= CON_SFR(gpio, cfg); + writel(value, &bank->con); +} + +void s5p_gpio_direction_output(struct s5p_gpio_bank *bank, int gpio, int en) +{ + unsigned int value; + + s5p_gpio_cfg_pin(bank, gpio, EXYNOS_GPIO_OUTPUT); + + value = readl(&bank->dat); + value &= ~DAT_MASK(gpio); + if (en) + value |= DAT_SET(gpio); + writel(value, &bank->dat); +} + +void s5p_gpio_direction_input(struct s5p_gpio_bank *bank, int gpio) +{ + s5p_gpio_cfg_pin(bank, gpio, EXYNOS_GPIO_INPUT); +} + +void s5p_gpio_set_value(struct s5p_gpio_bank *bank, int gpio, int en) +{ + unsigned int value; + + value = readl(&bank->dat); + value &= ~DAT_MASK(gpio); + if (en) + value |= DAT_SET(gpio); + writel(value, &bank->dat); +} + +unsigned int s5p_gpio_get_value(struct s5p_gpio_bank *bank, int gpio) +{ + unsigned int value; + + value = readl(&bank->dat); + return !!(value & DAT_MASK(gpio)); +} + +void s5p_gpio_set_pull(struct s5p_gpio_bank *bank, int gpio, int mode) +{ + unsigned int value; + + value = readl(&bank->pull); + value &= ~PULL_MASK(gpio); + + switch (mode) { + case EXYNOS_GPIO_PULL_DOWN: + case EXYNOS_GPIO_PULL_UP: + value |= PULL_MODE(gpio, mode); + break; + default: + break; + } + + writel(value, &bank->pull); +} + +void s5p_gpio_set_drv(struct s5p_gpio_bank *bank, int gpio, int mode) +{ + unsigned int value; + + value = readl(&bank->drv); + value &= ~DRV_MASK(gpio); + + switch (mode) { + case EXYNOS_GPIO_DRV_1X: + case EXYNOS_GPIO_DRV_2X: + case EXYNOS_GPIO_DRV_3X: + case EXYNOS_GPIO_DRV_4X: + value |= DRV_SET(gpio, mode); + break; + default: + return; + } + + writel(value, &bank->drv); +} + +void s5p_gpio_set_rate(struct s5p_gpio_bank *bank, int gpio, int mode) +{ + unsigned int value; + + value = readl(&bank->drv); + value &= ~RATE_MASK(gpio); + + switch (mode) { + case EXYNOS_GPIO_DRV_FAST: + case EXYNOS_GPIO_DRV_SLOW: + value |= RATE_SET(gpio); + break; + default: + return; + } + + writel(value, &bank->drv); +} + +/* Common GPIO API - only available on Exynos5 */ +/* FIXME(dhendrix): If this stuff is really only applicable to exynos5, + move it to a more sensible location. */ +#ifdef HAVE_GENERIC_GPIO + +void gpio_cfg_pin(int gpio, int cfg) +{ + unsigned int value; + struct s5p_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 s5p_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 s5p_gpio_bank *bank = gpio_get_bank(gpio); + + value = readl(&bank->pull); + value &= ~PULL_MASK(GPIO_BIT(gpio)); + + switch (mode) { + case EXYNOS_GPIO_PULL_DOWN: + case EXYNOS_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 s5p_gpio_bank *bank = gpio_get_bank(gpio); + + value = readl(&bank->drv); + value &= ~DRV_MASK(GPIO_BIT(gpio)); + + switch (mode) { + case EXYNOS_GPIO_DRV_1X: + case EXYNOS_GPIO_DRV_2X: + case EXYNOS_GPIO_DRV_3X: + case EXYNOS_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 s5p_gpio_bank *bank = gpio_get_bank(gpio); + + value = readl(&bank->drv); + value &= ~RATE_MASK(GPIO_BIT(gpio)); + + switch (mode) { + case EXYNOS_GPIO_DRV_FAST: + case EXYNOS_GPIO_DRV_SLOW: + value |= RATE_SET(GPIO_BIT(gpio)); + break; + default: + return; + } + + writel(value, &bank->drv); +} + +int gpio_request(unsigned gpio, const char *label) +{ + return 0; +} + +int gpio_free(unsigned gpio) +{ + return 0; +} + +int gpio_direction_input(unsigned gpio) +{ + gpio_cfg_pin(gpio, EXYNOS_GPIO_INPUT); + + return 0; +} + +int gpio_direction_output(unsigned gpio, int value) +{ + unsigned int val; + struct s5p_gpio_bank *bank = gpio_get_bank(gpio); + + gpio_cfg_pin(gpio, EXYNOS_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 s5p_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 s5p_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; +} +#else + +static int s5p_gpio_get_pin(unsigned gpio) +{ + return gpio % GPIO_PER_BANK; +} + +/* + * If we have the old-style GPIO numbering setup, use these functions + * which don't necessary provide sequentially increasing GPIO numbers. + */ +static struct s5p_gpio_bank *s5p_gpio_get_bank(unsigned gpio) +{ + int bank = gpio / GPIO_PER_BANK; + bank *= sizeof(struct s5p_gpio_bank); + + return (struct s5p_gpio_bank *) (s5p_gpio_base(gpio) + bank); +} + +int gpio_request(unsigned gpio, const char *label) +{ + return 0; +} + +int gpio_free(unsigned gpio) +{ + return 0; +} + +int gpio_direction_input(unsigned gpio) +{ + s5p_gpio_direction_input(s5p_gpio_get_bank(gpio), + s5p_gpio_get_pin(gpio)); + return 0; +} + +int gpio_direction_output(unsigned gpio, int value) +{ + s5p_gpio_direction_output(s5p_gpio_get_bank(gpio), + s5p_gpio_get_pin(gpio), value); + return 0; +} + +int gpio_get_value(unsigned gpio) +{ + return (int) s5p_gpio_get_value(s5p_gpio_get_bank(gpio), + s5p_gpio_get_pin(gpio)); +} + +int gpio_set_value(unsigned gpio, int value) +{ + s5p_gpio_set_value(s5p_gpio_get_bank(gpio), + s5p_gpio_get_pin(gpio), value); + + return 0; +} + +#endif /* HAVE_GENERIC_GPIO */ + +/* + * 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, EXYNOS_GPIO_PULL_UP); + udelay(GPIO_DELAY_US); + high = gpio_get_value(gpio); + gpio_set_pull(gpio, EXYNOS_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, EXYNOS_GPIO_PULL_UP); + + return value; +} + +int gpio_decode_number(unsigned gpio_list[], int count) +{ + int result = 0; + int multiplier = 1; + int gpio, i, value; + enum mvl3 mvl3; + + for (i = 0; i < count; i++) { + gpio = gpio_list[i]; + + mvl3 = gpio_read_mvl3(gpio); + if (mvl3 == LOGIC_1) + value = 2; + else if (mvl3 == LOGIC_0) + value = 1; + else if (mvl3 == LOGIC_Z) + value = 0; + else + return -1; + + result += value * multiplier; + multiplier *= 3; + } + + return result; +} +#endif /* __BOOT_BLOCK__ */ + +static const char *get_cfg_name(int cfg) +{ + static char name[8]; + + if (cfg == EXYNOS_GPIO_INPUT) + return "input"; + else if (cfg == EXYNOS_GPIO_OUTPUT) + return "output"; + printk(BIOS_INFO, "func %d", cfg); +// sprintf(name, "func %d", cfg); + + return name; +} + +/* + * 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: %s", gpio, get_cfg_name(cfg)); + if (cfg == EXYNOS_GPIO_INPUT || cfg == EXYNOS_GPIO_OUTPUT) + printk(BIOS_INFO, ", value = %d", gpio_get_value(gpio)); + printk(BIOS_INFO, "\n"); + } +} diff --git a/src/cpu/samsung/exynos5250/gpio.h b/src/cpu/samsung/exynos5250/gpio.h index 12143849f5..70e7f2d458 100644 --- a/src/cpu/samsung/exynos5250/gpio.h +++ b/src/cpu/samsung/exynos5250/gpio.h @@ -21,7 +21,241 @@ #ifndef EXYNOS5250_GPIO_H_ #define EXYNOS5250_GPIO_H_ -#include +#include /* FIXME: for S5PC110_GPIO_BASE */ + +struct s5p_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]; +}; + +struct s5pc100_gpio { + struct s5p_gpio_bank a0; + struct s5p_gpio_bank a1; + struct s5p_gpio_bank b; + struct s5p_gpio_bank c; + struct s5p_gpio_bank d; + struct s5p_gpio_bank e0; + struct s5p_gpio_bank e1; + struct s5p_gpio_bank f0; + struct s5p_gpio_bank f1; + struct s5p_gpio_bank f2; + struct s5p_gpio_bank f3; + struct s5p_gpio_bank g0; + struct s5p_gpio_bank g1; + struct s5p_gpio_bank g2; + struct s5p_gpio_bank g3; + struct s5p_gpio_bank i; + struct s5p_gpio_bank j0; + struct s5p_gpio_bank j1; + struct s5p_gpio_bank j2; + struct s5p_gpio_bank j3; + struct s5p_gpio_bank j4; + struct s5p_gpio_bank k0; + struct s5p_gpio_bank k1; + struct s5p_gpio_bank k2; + struct s5p_gpio_bank k3; + struct s5p_gpio_bank l0; + struct s5p_gpio_bank l1; + struct s5p_gpio_bank l2; + struct s5p_gpio_bank l3; + struct s5p_gpio_bank l4; + struct s5p_gpio_bank h0; + struct s5p_gpio_bank h1; + struct s5p_gpio_bank h2; + struct s5p_gpio_bank h3; +}; + +struct s5pc110_gpio { + struct s5p_gpio_bank a0; + struct s5p_gpio_bank a1; + struct s5p_gpio_bank b; + struct s5p_gpio_bank c0; + struct s5p_gpio_bank c1; + struct s5p_gpio_bank d0; + struct s5p_gpio_bank d1; + struct s5p_gpio_bank e0; + struct s5p_gpio_bank e1; + struct s5p_gpio_bank f0; + struct s5p_gpio_bank f1; + struct s5p_gpio_bank f2; + struct s5p_gpio_bank f3; + struct s5p_gpio_bank g0; + struct s5p_gpio_bank g1; + struct s5p_gpio_bank g2; + struct s5p_gpio_bank g3; + struct s5p_gpio_bank i; + struct s5p_gpio_bank j0; + struct s5p_gpio_bank j1; + struct s5p_gpio_bank j2; + struct s5p_gpio_bank j3; + struct s5p_gpio_bank j4; + struct s5p_gpio_bank mp0_1; + struct s5p_gpio_bank mp0_2; + struct s5p_gpio_bank mp0_3; + struct s5p_gpio_bank mp0_4; + struct s5p_gpio_bank mp0_5; + struct s5p_gpio_bank mp0_6; + struct s5p_gpio_bank mp0_7; + struct s5p_gpio_bank mp1_0; + struct s5p_gpio_bank mp1_1; + struct s5p_gpio_bank mp1_2; + struct s5p_gpio_bank mp1_3; + struct s5p_gpio_bank mp1_4; + struct s5p_gpio_bank mp1_5; + struct s5p_gpio_bank mp1_6; + struct s5p_gpio_bank mp1_7; + struct s5p_gpio_bank mp1_8; + struct s5p_gpio_bank mp2_0; + struct s5p_gpio_bank mp2_1; + struct s5p_gpio_bank mp2_2; + struct s5p_gpio_bank mp2_3; + struct s5p_gpio_bank mp2_4; + struct s5p_gpio_bank mp2_5; + struct s5p_gpio_bank mp2_6; + struct s5p_gpio_bank mp2_7; + struct s5p_gpio_bank mp2_8; + struct s5p_gpio_bank res1[48]; + struct s5p_gpio_bank h0; + struct s5p_gpio_bank h1; + struct s5p_gpio_bank h2; + struct s5p_gpio_bank h3; +}; + +/* functions */ +void s5p_gpio_cfg_pin(struct s5p_gpio_bank *bank, int gpio, int cfg); +void s5p_gpio_direction_output(struct s5p_gpio_bank *bank, int gpio, int en); +void s5p_gpio_direction_input(struct s5p_gpio_bank *bank, int gpio); +void s5p_gpio_set_value(struct s5p_gpio_bank *bank, int gpio, int en); +unsigned int s5p_gpio_get_value(struct s5p_gpio_bank *bank, int gpio); +void s5p_gpio_set_pull(struct s5p_gpio_bank *bank, int gpio, int mode); +void s5p_gpio_set_drv(struct s5p_gpio_bank *bank, int gpio, int mode); +void s5p_gpio_set_rate(struct s5p_gpio_bank *bank, int gpio, int mode); + +/* GPIO pins per bank */ +#define GPIO_PER_BANK 8 + +static inline unsigned int s5p_gpio_base(int nr) +{ + return S5PC110_GPIO_BASE; +} + +#define s5pc110_gpio_get_nr(bank, pin) \ + ((((((unsigned int)&(((struct s5pc110_gpio *)S5PC110_GPIO_BASE)->bank))\ + - S5PC110_GPIO_BASE) / sizeof(struct s5p_gpio_bank)) \ + * GPIO_PER_BANK) + pin) + +/* 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 0x2 + +/* 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 + +/* GPIO pins per bank */ +#define GPIO_PER_BANK 8 + +/* Pin configurations */ +#define EXYNOS_GPIO_INPUT 0x0 +#define EXYNOS_GPIO_OUTPUT 0x1 +#define EXYNOS_GPIO_IRQ 0xf +#define EXYNOS_GPIO_FUNC(x) (x) + +/* Pull mode */ +#define EXYNOS_GPIO_PULL_NONE 0x0 +#define EXYNOS_GPIO_PULL_DOWN 0x1 +#define EXYNOS_GPIO_PULL_UP 0x3 + +/* Drive Strength level */ +#define EXYNOS_GPIO_DRV_1X 0x0 +#define EXYNOS_GPIO_DRV_3X 0x1 +#define EXYNOS_GPIO_DRV_2X 0x2 +#define EXYNOS_GPIO_DRV_4X 0x3 +#define EXYNOS_GPIO_DRV_FAST 0x0 +#define EXYNOS_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, +}; struct exynos5_gpio_part1 { struct s5p_gpio_bank a0; diff --git a/src/cpu/samsung/exynos5250/i2c.c b/src/cpu/samsung/exynos5250/i2c.c new file mode 100644 index 0000000000..21c939432f --- /dev/null +++ b/src/cpu/samsung/exynos5250/i2c.c @@ -0,0 +1,414 @@ +/* + * (C) Copyright 2002 + * David Mueller, ELSOFT AG, d.mueller@elsoft.ch + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +/* This code should work for both the S3C2400 and the S3C2410 + * as they seem to have the same I2C controller inside. + * The different address mapping is handled by the s3c24xx.h files below. + */ + +#include +#include +#include +#include +#include "cpu/samsung/exynos5250/clk.h" +#include "cpu/samsung/exynos5250/i2c.h" +#include "cpu/samsung/exynos5250/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[] = { + /* FIXME: exynos5250-specific? */ + { + .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; +} diff --git a/src/cpu/samsung/exynos5250/i2c.h b/src/cpu/samsung/exynos5250/i2c.h new file mode 100644 index 0000000000..0bfee340e1 --- /dev/null +++ b/src/cpu/samsung/exynos5250/i2c.h @@ -0,0 +1,45 @@ +/* + * Copyright (C) 2012 Samsung Electronics + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#ifndef _S3C24X0_I2C_H +#define _S3C24X0_I2C_H + +/* FIXME: gross hack */ +#include "cpu/samsung/exynos5250/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 /* _S3C24X0_I2C_H */ diff --git a/src/cpu/samsung/exynos5250/pinmux.c b/src/cpu/samsung/exynos5250/pinmux.c index becced24d5..907ee80808 100644 --- a/src/cpu/samsung/exynos5250/pinmux.c +++ b/src/cpu/samsung/exynos5250/pinmux.c @@ -26,7 +26,7 @@ #include #include #include -#include +#include int exynos_pinmux_config(enum periph_id peripheral, int flags) { diff --git a/src/cpu/samsung/exynos5250/power.c b/src/cpu/samsung/exynos5250/power.c index 8aba0e86b6..ffba8c5f37 100644 --- a/src/cpu/samsung/exynos5250/power.c +++ b/src/cpu/samsung/exynos5250/power.c @@ -27,7 +27,6 @@ #include #include #include -#include #include #include #include diff --git a/src/cpu/samsung/exynos5250/power.h b/src/cpu/samsung/exynos5250/power.h index 20a884eefc..e82a94b7d8 100644 --- a/src/cpu/samsung/exynos5250/power.h +++ b/src/cpu/samsung/exynos5250/power.h @@ -21,6 +21,25 @@ #ifndef __EXYNOS5_POWER_H__ #define __EXYNOS5_POWER_H__ +/* + * Power control + */ +#define S5PC100_OTHERS 0xE0108200 +#define S5PC100_RST_STAT 0xE0108300 +#define S5PC100_SLEEP_WAKEUP (1 << 3) +#define S5PC100_WAKEUP_STAT 0xE0108304 +#define S5PC100_INFORM0 0xE0108400 + +#define S5PC110_RST_STAT 0xE010A000 +#define S5PC110_SLEEP_WAKEUP (1 << 3) +#define S5PC110_WAKEUP_STAT 0xE010C200 +#define S5PC110_OTHERS 0xE010E000 +#define S5PC110_USB_PHY_CON 0xE010E80C +#define S5PC110_INFORM0 0xE010F000 + +/* 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) diff --git a/src/cpu/samsung/exynos5250/pwm.c b/src/cpu/samsung/exynos5250/pwm.c new file mode 100644 index 0000000000..66a3b9dd3c --- /dev/null +++ b/src/cpu/samsung/exynos5250/pwm.c @@ -0,0 +1,199 @@ +/* + * Copyright (C) 2011 Samsung Electronics + * + * Donghwa Lee + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#include +#include +#include +#include +#include +#include + +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; +// return -ERANGE; + + if (duty_ns > period_ns) + return -1; +// return -EINVAL; + + 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; +} diff --git a/src/cpu/samsung/exynos5250/pwm.h b/src/cpu/samsung/exynos5250/pwm.h new file mode 100644 index 0000000000..d7aa76fd15 --- /dev/null +++ b/src/cpu/samsung/exynos5250/pwm.h @@ -0,0 +1,74 @@ +/* + * Copyright (C) 2009 Samsung Electronics + * Kyungmin Park + * Minkyu Kang + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#ifndef __ASM_ARM_ARCH_COMMON_PWM_H_ +#define __ASM_ARM_ARCH_COMMON_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) + +#ifndef __ASSEMBLER__ +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 /* __ASSEMBLER__ */ + +#endif diff --git a/src/cpu/samsung/exynos5250/reset.c b/src/cpu/samsung/exynos5250/reset.c new file mode 100644 index 0000000000..6cbc1d88e5 --- /dev/null +++ b/src/cpu/samsung/exynos5250/reset.c @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2010 Samsung Electronics. + * Minkyu Kang + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#include +#include + +void soft_reset(void) +{ + writel(0x1, samsung_get_base_swreset()); +} diff --git a/src/cpu/samsung/exynos5250/s5p-dp-core.h b/src/cpu/samsung/exynos5250/s5p-dp-core.h new file mode 100644 index 0000000000..e7a1bd8c7d --- /dev/null +++ b/src/cpu/samsung/exynos5250/s5p-dp-core.h @@ -0,0 +1,259 @@ +/* + * Header file for Samsung DP (Display Port) interface driver. + * + * Copyright 2013 Google Inc. + * Copyright (C) 2012 Samsung Electronics Co., Ltd. + * Author: Jingoo Han + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ + +#ifndef _S5P_DP_CORE_H +#define _S5P_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 /* _S5P_DP_CORE_H */ diff --git a/src/cpu/samsung/exynos5250/s5p-dp-reg.c b/src/cpu/samsung/exynos5250/s5p-dp-reg.c new file mode 100644 index 0000000000..559019785d --- /dev/null +++ b/src/cpu/samsung/exynos5250/s5p-dp-reg.c @@ -0,0 +1,486 @@ +/* + * Samsung DP (Display port) register interface driver. + * + * Copyright (C) 2012 Samsung Electronics Co., Ltd. + * Author: Jingoo Han + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ + +#include +#include +#include +#include +#include +#include +#include "cpu/samsung/exynos5250/fimd.h" +#include "s5p-dp-core.h" + +#include + +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); +} diff --git a/src/cpu/samsung/exynos5250/spi.c b/src/cpu/samsung/exynos5250/spi.c new file mode 100644 index 0000000000..33f4d99fd2 --- /dev/null +++ b/src/cpu/samsung/exynos5250/spi.c @@ -0,0 +1,227 @@ +/* + * Copyright (C) 2011 Samsung Electronics + * Copyright (C) 2013 The Chromium OS Authors. All rights reserved. + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#include + +#include +#include + +#include +#include + +#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); +} diff --git a/src/cpu/samsung/exynos5250/spi.h b/src/cpu/samsung/exynos5250/spi.h index 20f50e58c6..3892917025 100644 --- a/src/cpu/samsung/exynos5250/spi.h +++ b/src/cpu/samsung/exynos5250/spi.h @@ -20,6 +20,9 @@ #ifndef __ASM_ARCH_EXYNOS_COMMON_SPI_H_ #define __ASM_ARCH_EXYNOS_COMMON_SPI_H_ +// This driver serves as a CBFS media source. +#include + #ifndef __ASSEMBLER__ /* SPI peripheral register map; padded to 64KB */ @@ -85,5 +88,16 @@ struct exynos_spi { #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 */ +int initialize_exynos_spi_cbfs_media(struct cbfs_media *media, + void *buffer_address, + size_t buffer_size); + #endif /* __ASSEMBLER__ */ + #endif diff --git a/src/cpu/samsung/exynos5250/sromc.c b/src/cpu/samsung/exynos5250/sromc.c new file mode 100644 index 0000000000..7bc93e7862 --- /dev/null +++ b/src/cpu/samsung/exynos5250/sromc.c @@ -0,0 +1,49 @@ +/* + * Copyright (C) 2010 Samsung Electronics + * Naveen Krishna Ch + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#include +#include +#include + +/* + * s5p_config_sromc() - select the proper SROMC Bank and configure the + * band width control and bank control registers + * srom_bank - SROM + * srom_bw_conf - SMC Band witdh reg configuration value + * srom_bc_conf - SMC Bank Control reg configuration value + */ +void s5p_config_sromc(u32 srom_bank, u32 srom_bw_conf, u32 srom_bc_conf) +{ + u32 tmp; + struct s5p_sromc *srom = + samsung_get_base_sromc(); + + /* Configure SMC_BW register to handle proper SROMC bank */ + tmp = srom->bw; + tmp &= ~(0xF << (srom_bank * 4)); + tmp |= srom_bw_conf; + srom->bw = tmp; + + /* Configure SMC_BC register */ + srom->bc[srom_bank] = srom_bc_conf; +} diff --git a/src/cpu/samsung/exynos5250/sromc.h b/src/cpu/samsung/exynos5250/sromc.h new file mode 100644 index 0000000000..d4fdae90e6 --- /dev/null +++ b/src/cpu/samsung/exynos5250/sromc.h @@ -0,0 +1,69 @@ +/* + * (C) Copyright 2010 Samsung Electronics + * Naveen Krishna 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; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * Note: This file contains the register description for SROMC + * + */ + +#ifndef __ASM_ARCH_COMMON_SROMC_H_ +#define __ASM_ARCH_COMMON_SROMC_H_ + +#define SROMC_DATA16_WIDTH(x) (1<<((x*4)+0)) +#define SROMC_BYTE_ADDR_MODE(x) (1<<((x*4)+1)) /* 0-> Half-word base address*/ + /* 1-> Byte base address*/ +#define SROMC_WAIT_ENABLE(x) (1<<((x*4)+2)) +#define SROMC_BYTE_ENABLE(x) (1<<((x*4)+3)) + +#define SROMC_BC_TACS(x) (x << 28) /* address set-up */ +#define SROMC_BC_TCOS(x) (x << 24) /* chip selection set-up */ +#define SROMC_BC_TACC(x) (x << 16) /* access cycle */ +#define SROMC_BC_TCOH(x) (x << 12) /* chip selection hold */ +#define SROMC_BC_TAH(x) (x << 8) /* address holding time */ +#define SROMC_BC_TACP(x) (x << 4) /* page mode access cycle */ +#define SROMC_BC_PMC(x) (x << 0) /* normal(1data)page mode configuration */ + +#ifndef __ASSEMBLER__ +struct s5p_sromc { + unsigned int bw; + unsigned int bc[4]; +}; +#endif /* __ASSEMBLER__ */ + +/* Configure the Band Width and Bank Control Regs for required SROMC Bank */ +void s5p_config_sromc(u32 srom_bank, u32 srom_bw_conf, u32 srom_bc_conf); + +enum { + FDT_SROM_PMC, + FDT_SROM_TACP, + FDT_SROM_TAH, + FDT_SROM_TCOH, + FDT_SROM_TACC, + FDT_SROM_TCOS, + FDT_SROM_TACS, + + FDT_SROM_TIMING_COUNT, +}; + +struct fdt_sromc { + u8 bank; /* srom bank number */ + u8 width; /* bus width in bytes */ + unsigned int timing[FDT_SROM_TIMING_COUNT]; /* timing parameters */ +}; + +#endif /* __ASM_ARCH_COMMON_SROMC_H_ */ diff --git a/src/cpu/samsung/exynos5250/timer.c b/src/cpu/samsung/exynos5250/timer.c new file mode 100644 index 0000000000..e7cadc3b9d --- /dev/null +++ b/src/cpu/samsung/exynos5250/timer.c @@ -0,0 +1,164 @@ +/* + * Copyright (C) 2009 Samsung Electronics + * Heungjun Kim + * Inki Dae + * Minkyu Kang + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +//#include + +//DECLARE_GLOBAL_DATA_PTR; +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); +} + +int 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 */ + //gd->timer_reset_value = 0; + timer_reset_value = 0; + + /* Use this as the last timer value we saw */ + //gd->lastinc = timer_get_us_down(); + lastinc = timer_get_us_down(); + } + + return 0; +} + +/* + * 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. + */ +#if 0 + gd->timer_reset_value += gd->lastinc - now; + gd->lastinc = now; + + /* Divide by 1000 to convert from us to ms */ + return gd->timer_reset_value / 1000 - base; +#endif + timer_reset_value += lastinc - now; + lastinc = now; + + /* Divide by 1000 to convert from us to ms */ + return timer_reset_value / 1000 - base; +} + +unsigned long timer_get_us(void) +{ + struct s5p_timer *const timer = s5p_get_base_timer(); + unsigned long now_downward_us = readl(&timer->tcnto4); + + /* + * Note that this timer counts downward. The pre-SPL process (BL1) + * takes about 100ms, so add this in here. + */ + return CONFIG_SPL_TIME_US - now_downward_us; +} + +/* delay x useconds */ +void udelay(unsigned long 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%08lx 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); +} + +/* + * This function is derived from PowerPC code (read timebase as long long). + * On ARM it just returns the timer value. + */ +unsigned long long get_ticks(void) +{ + return get_timer(0); +} + +/* + * This function is derived from PowerPC code (timebase clock frequency). + * On ARM it returns the number of timer ticks per second. + */ +unsigned long get_tbclk(void) +{ + return CONFIG_SYS_HZ; +} + +unsigned long timer_get_boot_us(void) +{ + return timer_get_us(); +} diff --git a/src/cpu/samsung/exynos5250/uart.c b/src/cpu/samsung/exynos5250/uart.c index 34d8e08e3b..e6d9654b7e 100644 --- a/src/cpu/samsung/exynos5250/uart.c +++ b/src/cpu/samsung/exynos5250/uart.c @@ -27,8 +27,7 @@ #include /* for __console definition */ -#include -#include +#include #include #include diff --git a/src/cpu/samsung/exynos5250/uart.h b/src/cpu/samsung/exynos5250/uart.h index 1d872d705f..aea4a62ca7 100644 --- a/src/cpu/samsung/exynos5250/uart.h +++ b/src/cpu/samsung/exynos5250/uart.h @@ -32,4 +32,33 @@ #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]; +}; + +static inline int s5p_uart_divslot(void) +{ + return 0; +} + #endif diff --git a/src/cpu/samsung/exynos5250/wakeup.c b/src/cpu/samsung/exynos5250/wakeup.c index 1e8d892bc8..5a13191d58 100644 --- a/src/cpu/samsung/exynos5250/wakeup.c +++ b/src/cpu/samsung/exynos5250/wakeup.c @@ -19,7 +19,7 @@ #include #include -#include +#include #include "wakeup.h" diff --git a/src/cpu/samsung/exynos5250/watchdog.h b/src/cpu/samsung/exynos5250/watchdog.h new file mode 100644 index 0000000000..5b3b651ffa --- /dev/null +++ b/src/cpu/samsung/exynos5250/watchdog.h @@ -0,0 +1,57 @@ +/* + * Copyright (C) 2011 Samsung Electronics + * Heungjun Kim + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#ifndef __ASM_ARM_ARCH_COMMON_WATCHDOG_H_ +#define __ASM_ARM_ARCH_COMMON_WATCHDOG_H_ + +#define WTCON_RESET_OFFSET 0 +#define WTCON_INTEN_OFFSET 2 +#define WTCON_CLKSEL_OFFSET 3 +#define WTCON_EN_OFFSET 5 +#define WTCON_PRE_OFFSET 8 + +#define WTCON_CLK_16 0x0 +#define WTCON_CLK_32 0x1 +#define WTCON_CLK_64 0x2 +#define WTCON_CLK_128 0x3 + +#define WTCON_CLK(x) ((x & 0x3) << WTCON_CLKSEL_OFFSET) +#define WTCON_PRESCALER(x) ((x) << WTCON_PRE_OFFSET) +#define WTCON_EN (0x1 << WTCON_EN_OFFSET) +#define WTCON_RESET (0x1 << WTCON_RESET_OFFSET) +#define WTCON_INT (0x1 << WTCON_INTEN_OFFSET) + +#ifndef __ASSEMBLER__ +struct s5p_watchdog { + unsigned int wtcon; + unsigned int wtdat; + unsigned int wtcnt; + unsigned int wtclrint; +}; + +/* functions */ +void wdt_stop(void); +void wdt_start(unsigned int timeout); +#endif /* __ASSEMBLER__ */ + +#endif diff --git a/src/cpu/samsung/exynos5250/wdt.c b/src/cpu/samsung/exynos5250/wdt.c new file mode 100644 index 0000000000..dbeefec49a --- /dev/null +++ b/src/cpu/samsung/exynos5250/wdt.c @@ -0,0 +1,59 @@ +/* + * Copyright (C) 2012 Samsung Electronics + * Minkyu Kang + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#include +#include +#include + +#define PRESCALER_VAL 255 + +void wdt_stop(void) +{ + struct s5p_watchdog *wdt = + samsung_get_base_watchdog(); + unsigned int wtcon; + + wtcon = readl(&wdt->wtcon); + wtcon &= ~(WTCON_EN | WTCON_INT | WTCON_RESET); + + writel(wtcon, &wdt->wtcon); +} + +void wdt_start(unsigned int timeout) +{ + struct s5p_watchdog *wdt = + samsung_get_base_watchdog(); + unsigned int wtcon; + + wdt_stop(); + + wtcon = readl(&wdt->wtcon); + wtcon |= (WTCON_EN | WTCON_CLK(WTCON_CLK_128)); + wtcon &= ~WTCON_INT; + wtcon |= WTCON_RESET; + wtcon |= WTCON_PRESCALER(PRESCALER_VAL); + + writel(timeout, &wdt->wtdat); + writel(timeout, &wdt->wtcnt); + writel(wtcon, &wdt->wtcon); +} -- cgit v1.2.3