Xilinx changes for v2017.09

Zynq:
 - Add Z-Turn board support
 
 fpga:
 - Remove intermediate buffer from code
 
 Zynqmp:
 - dts cleanup
 - change psu_init handling
 - Add options to get silicon version
 - Fix time handling
 - Map OCM/TCM via MMU
 - Add new clock driver
 -----BEGIN PGP SIGNATURE-----
 Version: GnuPG v1
 
 iEYEABECAAYFAlmBs2kACgkQykllyylKDCFUGgCgmfop8Ki5+6QI7XQRP7u8nhjw
 KakAn1sYIRDFQ34AoxmiYa6RTmjepLMv
 =1Gh3
 -----END PGP SIGNATURE-----

Merge tag 'xilinx-for-v2017.09' of git://www.denx.de/git/u-boot-microblaze

Xilinx changes for v2017.09

Zynq:
- Add Z-Turn board support

fpga:
- Remove intermediate buffer from code

Zynqmp:
- dts cleanup
- change psu_init handling
- Add options to get silicon version
- Fix time handling
- Map OCM/TCM via MMU
- Add new clock driver
This commit is contained in:
Tom Rini 2017-08-04 07:23:32 -04:00
commit fe84c48eeb
22 changed files with 1053 additions and 253 deletions

View file

@ -56,6 +56,17 @@ config ZYNQMP_USB
config SYS_MALLOC_F_LEN
default 0x600
config DEFINE_TCM_OCM_MMAP
bool "Define TCM and OCM memory in MMU Table"
help
This option if enabled defines the TCM and OCM memory and its
memory attributes in MMU table entry.
config ZYNQMP_PSU_INIT_ENABLED
bool "Include psu_init"
help
Include psu_init to full u-boot. SPL include psu_init by default.
config SPL_ZYNQMP_ALT_BOOTMODE_ENABLED
bool "Overwrite SPL bootmode"
depends on SPL

View file

@ -38,6 +38,14 @@ static struct mm_region zynqmp_mem_map[] = {
PTE_BLOCK_NON_SHARE |
PTE_BLOCK_PXN | PTE_BLOCK_UXN
}, {
#if defined(CONFIG_DEFINE_TCM_OCM_MMAP)
.virt = 0xffe00000UL,
.phys = 0xffe00000UL,
.size = 0x00200000UL,
.attrs = PTE_BLOCK_MEMTYPE(MT_NORMAL) |
PTE_BLOCK_INNER_SHARE
}, {
#endif
.virt = 0x400000000UL,
.phys = 0x400000000UL,
.size = 0x200000000UL,
@ -102,9 +110,8 @@ unsigned int zynqmp_get_silicon_version(void)
#define ZYNQMP_MMIO_READ 0xC2000014
#define ZYNQMP_MMIO_WRITE 0xC2000013
#ifndef CONFIG_SPL_BUILD
int invoke_smc(u32 pm_api_id, u32 arg0, u32 arg1, u32 arg2, u32 arg3,
u32 *ret_payload)
int __maybe_unused invoke_smc(u32 pm_api_id, u32 arg0, u32 arg1, u32 arg2,
u32 arg3, u32 *ret_payload)
{
/*
* Added SIP service call Function Identifier
@ -164,28 +171,7 @@ void zynqmp_pmufw_version(void)
}
#endif
int zynqmp_mmio_write(const u32 address,
const u32 mask,
const u32 value)
{
return invoke_smc(ZYNQMP_MMIO_WRITE, address, mask, value, 0, NULL);
}
int zynqmp_mmio_read(const u32 address, u32 *value)
{
u32 ret_payload[PAYLOAD_ARG_CNT];
u32 ret;
if (!value)
return -EINVAL;
ret = invoke_smc(ZYNQMP_MMIO_READ, address, 0, 0, 0, ret_payload);
*value = ret_payload[1];
return ret;
}
#else
int zynqmp_mmio_write(const u32 address,
static int zynqmp_mmio_rawwrite(const u32 address,
const u32 mask,
const u32 value)
{
@ -200,9 +186,40 @@ int zynqmp_mmio_write(const u32 address,
return 0;
}
int zynqmp_mmio_read(const u32 address, u32 *value)
static int zynqmp_mmio_rawread(const u32 address, u32 *value)
{
*value = readl((ulong)address);
return 0;
}
#endif
int zynqmp_mmio_write(const u32 address,
const u32 mask,
const u32 value)
{
if (IS_ENABLED(CONFIG_SPL_BUILD) || current_el() == 3)
return zynqmp_mmio_rawwrite(address, mask, value);
else if (!IS_ENABLED(CONFIG_SPL_BUILD))
return invoke_smc(ZYNQMP_MMIO_WRITE, address, mask,
value, 0, NULL);
return -EINVAL;
}
int zynqmp_mmio_read(const u32 address, u32 *value)
{
u32 ret_payload[PAYLOAD_ARG_CNT];
u32 ret;
if (!value)
return -EINVAL;
if (IS_ENABLED(CONFIG_SPL_BUILD) || current_el() == 3) {
ret = zynqmp_mmio_rawread(address, value);
} else if (!IS_ENABLED(CONFIG_SPL_BUILD)) {
ret = invoke_smc(ZYNQMP_MMIO_READ, address, 0, 0,
0, ret_payload);
*value = ret_payload[1];
}
return ret;
}

View file

@ -206,6 +206,21 @@ static void write_tcm_boot_trampoline(u32 boot_addr)
}
}
void initialize_tcm(bool mode)
{
if (!mode) {
set_r5_tcm_mode(LOCK);
set_r5_halt_mode(HALT, LOCK);
enable_clock_r5();
release_r5_reset(LOCK);
} else {
set_r5_tcm_mode(SPLIT);
set_r5_halt_mode(HALT, SPLIT);
enable_clock_r5();
release_r5_reset(SPLIT);
}
}
int cpu_release(int nr, int argc, char * const argv[])
{
if (nr >= ZYNQMP_CORE_APU0 && nr <= ZYNQMP_CORE_APU3) {

View file

@ -17,7 +17,7 @@
void board_init_f(ulong dummy)
{
psu_init();
board_early_init_f();
board_early_init_r();
#ifdef CONFIG_DEBUG_UART

View file

@ -132,13 +132,14 @@ dtb-$(CONFIG_ARCH_ZYNQ) += zynq-zc702.dtb \
zynq-topic-miami.dtb \
zynq-topic-miamilite.dtb \
zynq-topic-miamiplus.dtb \
zynq-zturn-myir.dtb \
zynq-zc770-xm010.dtb \
zynq-zc770-xm011.dtb \
zynq-zc770-xm012.dtb \
zynq-zc770-xm013.dtb
dtb-$(CONFIG_ARCH_ZYNQMP) += \
zynqmp-ep108.dtb \
zynqmp-zcu102.dtb \
zynqmp-zcu102-revA.dtb \
zynqmp-zcu102-revB.dtb \
zynqmp-zc1751-xm015-dc1.dtb \
zynqmp-zc1751-xm016-dc2.dtb \

View file

@ -38,6 +38,14 @@
};
};
fpga_full: fpga-full {
compatible = "fpga-region";
fpga-mgr = <&devcfg>;
#address-cells = <1>;
#size-cells = <1>;
ranges;
};
pmu@f8891000 {
compatible = "arm,cortex-a9-pmu";
interrupts = <0 5 4>, <0 6 4>;

View file

@ -0,0 +1,161 @@
/*
* Copyright (C) 2015 Andrea Merello <adnrea.merello@gmail.com>
* Copyright (C) 2017 Alexander Graf <agraf@suse.de>
*
* Based on zynq-zed.dts which is:
* Copyright (C) 2011 - 2014 Xilinx
* Copyright (C) 2012 National Instruments Corp.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
* may be copied, distributed, and modified under those terms.
*
* 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.
*/
/dts-v1/;
/include/ "zynq-7000.dtsi"
/ {
model = "Zynq Z-Turn MYIR Board";
compatible = "xlnx,zynq-7000";
aliases {
ethernet0 = &gem0;
serial0 = &uart1;
serial1 = &uart0;
spi0 = &qspi;
mmc0 = &sdhci0;
};
memory {
device_type = "memory";
reg = <0x0 0x40000000>;
};
chosen {
stdout-path = "serial0:115200n8";
};
gpio-leds {
compatible = "gpio-leds";
led_r {
label = "led_r";
gpios = <&gpio0 0x72 0x1>;
default-state = "on";
linux,default-trigger = "heartbeat";
};
led_g {
label = "led_g";
gpios = <&gpio0 0x73 0x1>;
default-state = "on";
linux,default-trigger = "heartbeat";
};
led_b {
label = "led_b";
gpios = <&gpio0 0x74 0x1>;
default-state = "on";
linux,default-trigger = "heartbeat";
};
usr_led1 {
label = "usr_led1";
gpios = <&gpio0 0x0 0x1>;
default-state = "off";
linux,default-trigger = "none";
};
usr_led2 {
label = "usr_led2";
gpios = <&gpio0 0x9 0x1>;
default-state = "off";
linux,default-trigger = "none";
};
};
gpio-beep {
compatible = "gpio-beeper";
label = "pl-beep";
gpios = <&gpio0 0x75 0x0>;
};
gpio-keys {
compatible = "gpio-keys";
#address-cells = <0x1>;
#size-cells = <0x0>;
autorepeat;
K1 {
label = "K1";
gpios = <&gpio0 0x32 0x1>;
linux,code = <0x66>;
gpio-key,wakeup;
autorepeat;
};
};
};
&clkc {
ps-clk-frequency = <33333333>;
fclk-enable = <0xf>;
};
&qspi {
u-boot,dm-pre-reloc;
status = "okay";
};
&gem0 {
status = "okay";
phy-mode = "rgmii-id";
phy-handle = <&ethernet_phy>;
ethernet_phy: ethernet-phy@0 {
reg = <0x0>;
};
};
&sdhci0 {
u-boot,dm-pre-reloc;
status = "okay";
};
&uart0 {
u-boot,dm-pre-reloc;
status = "okay";
};
&uart1 {
u-boot,dm-pre-reloc;
status = "okay";
};
&usb0 {
status = "okay";
dr_mode = "host";
};
&can0 {
status = "okay";
};
&i2c0 {
status = "okay";
clock-frequency = <400000>;
stlm75@49 {
status = "okay";
compatible = "lm75";
reg = <0x49>;
};
adxl345@53 {
compatible = "adi,adxl34x", "adxl34x";
reg = <0x53>;
interrupt-parent = <&intc>;
interrupts = <0x0 0x1e 0x4>;
};
};

View file

@ -16,7 +16,7 @@
/ {
model = "ZynqMP ZCU102 RevA";
compatible = "xlnx,zynqmp-zcu102", "xlnx,zynqmp";
compatible = "xlnx,zynqmp-zcu102-revA", "xlnx,zynqmp-zcu102", "xlnx,zynqmp";
aliases {
ethernet0 = &gem3;

View file

@ -8,7 +8,7 @@
* SPDX-License-Identifier: GPL-2.0+
*/
#include "zynqmp-zcu102.dts"
#include "zynqmp-zcu102-revA.dts"
/ {
model = "ZynqMP ZCU102 RevB";

View file

@ -48,18 +48,9 @@ struct crlapb_regs {
#define crlapb_base ((struct crlapb_regs *)ZYNQMP_CRL_APB_BASEADDR)
#define ZYNQMP_IOU_SCNTR_SECURE 0xFF260000
#define ZYNQMP_IOU_SCNTR 0xFF250000
#define ZYNQMP_IOU_SCNTR_COUNTER_CONTROL_REGISTER_EN 0x1
#define ZYNQMP_IOU_SCNTR_COUNTER_CONTROL_REGISTER_HDBG 0x2
struct iou_scntr {
u32 counter_control_register;
u32 reserved0[7];
u32 base_frequency_id_register;
};
#define iou_scntr ((struct iou_scntr *)ZYNQMP_IOU_SCNTR)
struct iou_scntr_secure {
u32 counter_control_register;
u32 reserved0[7];
@ -153,4 +144,7 @@ struct pmu_regs {
#define pmu_base ((struct pmu_regs *)ZYNQMP_PMU_BASEADDR)
#define ZYNQMP_CSU_IDCODE_ADDR 0xFFCA0040
#define ZYNQMP_CSU_VER_ADDR 0xFFCA0044
#endif /* _ASM_ARCH_HARDWARE_H */

View file

@ -10,6 +10,25 @@
#define PAYLOAD_ARG_CNT 5
#define ZYNQMP_CSU_SILICON_VER_MASK 0xF
enum {
IDCODE,
VERSION,
};
enum {
ZYNQMP_SILICON_V1,
ZYNQMP_SILICON_V2,
ZYNQMP_SILICON_V3,
ZYNQMP_SILICON_V4,
};
enum {
TCM_LOCK,
TCM_SPLIT,
};
int zynq_slcr_get_mio_pin_status(const char *periph);
unsigned int zynqmp_get_silicon_version(void);
@ -24,4 +43,8 @@ int zynqmp_mmio_read(const u32 address, u32 *value);
int invoke_smc(u32 pm_api_id, u32 arg0, u32 arg1, u32 arg2, u32 arg3,
u32 *ret_payload);
void initialize_tcm(bool mode);
int chip_id(unsigned char id);
#endif /* _ASM_ARCH_SYS_PROTO_H */

View file

@ -42,6 +42,35 @@ SECTIONS
. = ALIGN(4);
.__efi_runtime_start : {
*(.__efi_runtime_start)
}
.efi_runtime : {
*(efi_runtime_text)
*(efi_runtime_data)
}
.__efi_runtime_stop : {
*(.__efi_runtime_stop)
}
.efi_runtime_rel_start :
{
*(.__efi_runtime_rel_start)
}
.efi_runtime_rel : {
*(.relefi_runtime_text)
*(.relefi_runtime_data)
}
.efi_runtime_rel_stop :
{
*(.__efi_runtime_rel_stop)
}
. = ALIGN(4);
.image_copy_end :
{
*(.__image_copy_end)

View file

@ -20,7 +20,11 @@ $(warning Put custom psu_init_gpl.c/h to board/xilinx/zynqmp/custom_hw_platform/
endif
endif
obj-$(CONFIG_SPL_BUILD) += $(init-objs)
ifdef_any_of = $(filter-out undefined,$(foreach v,$(1),$(origin $(v))))
ifneq ($(call ifdef_any_of, CONFIG_ZYNQMP_PSU_INIT_ENABLED CONFIG_SPL_BUILD),)
obj-y += $(init-objs)
endif
# Suppress "warning: function declaration isn't a prototype"
CFLAGS_REMOVE_psu_init_gpl.o := -Wstrict-prototypes

View file

@ -75,36 +75,70 @@ static const struct {
.name = "17eg",
},
};
#endif
static int chip_id(void)
int chip_id(unsigned char id)
{
struct pt_regs regs;
regs.regs[0] = ZYNQMP_SIP_SVC_CSU_DMA_CHIPID;
regs.regs[1] = 0;
regs.regs[2] = 0;
regs.regs[3] = 0;
int val = -EINVAL;
smc_call(&regs);
if (current_el() != 3) {
regs.regs[0] = ZYNQMP_SIP_SVC_CSU_DMA_CHIPID;
regs.regs[1] = 0;
regs.regs[2] = 0;
regs.regs[3] = 0;
/*
* SMC returns:
* regs[0][31:0] = status of the operation
* regs[0][63:32] = CSU.IDCODE register
* regs[1][31:0] = CSU.version register
*/
regs.regs[0] = upper_32_bits(regs.regs[0]);
regs.regs[0] &= ZYNQMP_CSU_IDCODE_DEVICE_CODE_MASK |
ZYNQMP_CSU_IDCODE_SVD_MASK;
regs.regs[0] >>= ZYNQMP_CSU_IDCODE_SVD_SHIFT;
smc_call(&regs);
return regs.regs[0];
/*
* SMC returns:
* regs[0][31:0] = status of the operation
* regs[0][63:32] = CSU.IDCODE register
* regs[1][31:0] = CSU.version register
*/
switch (id) {
case IDCODE:
regs.regs[0] = upper_32_bits(regs.regs[0]);
regs.regs[0] &= ZYNQMP_CSU_IDCODE_DEVICE_CODE_MASK |
ZYNQMP_CSU_IDCODE_SVD_MASK;
regs.regs[0] >>= ZYNQMP_CSU_IDCODE_SVD_SHIFT;
val = regs.regs[0];
break;
case VERSION:
regs.regs[1] = lower_32_bits(regs.regs[1]);
regs.regs[1] &= ZYNQMP_CSU_SILICON_VER_MASK;
val = regs.regs[1];
break;
default:
printf("%s, Invalid Req:0x%x\n", __func__, id);
}
} else {
switch (id) {
case IDCODE:
val = readl(ZYNQMP_CSU_IDCODE_ADDR);
val &= ZYNQMP_CSU_IDCODE_DEVICE_CODE_MASK |
ZYNQMP_CSU_IDCODE_SVD_MASK;
val >>= ZYNQMP_CSU_IDCODE_SVD_SHIFT;
break;
case VERSION:
val = readl(ZYNQMP_CSU_VER_ADDR);
val &= ZYNQMP_CSU_SILICON_VER_MASK;
break;
default:
printf("%s, Invalid Req:0x%x\n", __func__, id);
}
}
return val;
}
#if defined(CONFIG_FPGA) && defined(CONFIG_FPGA_ZYNQMPPL) && \
!defined(CONFIG_SPL_BUILD)
static char *zynqmp_get_silicon_idcode_name(void)
{
uint32_t i, id;
id = chip_id();
id = chip_id(IDCODE);
for (i = 0; i < ARRAY_SIZE(zynqmp_devices); i++) {
if (zynqmp_devices[i].id == id)
return zynqmp_devices[i].name;
@ -118,6 +152,11 @@ int board_early_init_f(void)
#if !defined(CONFIG_SPL_BUILD) && defined(CONFIG_CLK_ZYNQMP)
zynqmp_pmufw_version();
#endif
#if defined(CONFIG_SPL_BUILD) || defined(CONFIG_ZYNQMP_PSU_INIT_ENABLED)
psu_init();
#endif
return 0;
}
@ -133,10 +172,10 @@ int board_init(void)
if (current_el() != 3) {
static char version[ZYNQMP_VERSION_SIZE];
strncat(version, "xczu", ZYNQMP_VERSION_SIZE);
strncat(version, "xczu", 4);
zynqmppl.name = strncat(version,
zynqmp_get_silicon_idcode_name(),
ZYNQMP_VERSION_SIZE);
ZYNQMP_VERSION_SIZE - 5);
printf("Chip ID:\t%s\n", zynqmppl.name);
fpga_init();
fpga_add(fpga_xilinx, &zynqmppl);
@ -150,7 +189,10 @@ int board_early_init_r(void)
{
u32 val;
if (current_el() == 3) {
val = readl(&crlapb_base->timestamp_ref_ctrl);
val &= ZYNQMP_CRL_APB_TIMESTAMP_REF_CTRL_CLKACT;
if (current_el() == 3 && !val) {
val = readl(&crlapb_base->timestamp_ref_ctrl);
val |= ZYNQMP_CRL_APB_TIMESTAMP_REF_CTRL_CLKACT;
writel(val, &crlapb_base->timestamp_ref_ctrl);
@ -162,12 +204,6 @@ int board_early_init_r(void)
writel(ZYNQMP_IOU_SCNTR_COUNTER_CONTROL_REGISTER_EN,
&iou_scntr_secure->counter_control_register);
}
/* Program freq register in System counter and enable system counter */
writel(gd->cpu_clk, &iou_scntr->base_frequency_id_register);
writel(ZYNQMP_IOU_SCNTR_COUNTER_CONTROL_REGISTER_HDBG |
ZYNQMP_IOU_SCNTR_COUNTER_CONTROL_REGISTER_EN,
&iou_scntr->counter_control_register);
return 0;
}

View file

@ -340,7 +340,7 @@ static int reserve_round_4k(void)
}
#ifdef CONFIG_ARM
static int reserve_mmu(void)
__weak int reserve_mmu(void)
{
#if !(defined(CONFIG_SYS_ICACHE_OFF) && defined(CONFIG_SYS_DCACHE_OFF))
/* reserve TLB table */

View file

@ -5,7 +5,7 @@ CONFIG_SYS_TEXT_BASE=0x8000000
CONFIG_SYS_MALLOC_F_LEN=0x8000
CONFIG_IDENT_STRING=" Xilinx ZynqMP ZCU102"
CONFIG_ZYNQMP_USB=y
CONFIG_DEFAULT_DEVICE_TREE="zynqmp-zcu102"
CONFIG_DEFAULT_DEVICE_TREE="zynqmp-zcu102-revA"
CONFIG_DEBUG_UART=y
CONFIG_AHCI=y
CONFIG_DISTRO_DEFAULTS=y

View file

@ -0,0 +1,59 @@
CONFIG_ARM=y
CONFIG_ARCH_ZYNQ=y
CONFIG_SYS_TEXT_BASE=0x4000000
CONFIG_DEFAULT_DEVICE_TREE="zynq-zturn-myir"
CONFIG_DEBUG_UART=y
CONFIG_FIT=y
CONFIG_FIT_SIGNATURE=y
CONFIG_FIT_VERBOSE=y
CONFIG_ENV_IS_NOWHERE=y
# CONFIG_DISPLAY_CPUINFO is not set
CONFIG_SPL=y
CONFIG_SPL_OS_BOOT=y
CONFIG_HUSH_PARSER=y
CONFIG_SYS_PROMPT="Zynq> "
# CONFIG_CMD_IMLS is not set
# CONFIG_CMD_FLASH is not set
CONFIG_CMD_MMC=y
CONFIG_CMD_SF=y
CONFIG_CMD_USB=y
CONFIG_CMD_DFU=y
CONFIG_CMD_GPIO=y
# CONFIG_CMD_SETEXPR is not set
CONFIG_CMD_TFTPPUT=y
CONFIG_CMD_DHCP=y
CONFIG_CMD_MII=y
CONFIG_CMD_PING=y
CONFIG_CMD_CACHE=y
CONFIG_CMD_EXT2=y
CONFIG_CMD_EXT4=y
CONFIG_CMD_EXT4_WRITE=y
CONFIG_CMD_FAT=y
CONFIG_CMD_FS_GENERIC=y
CONFIG_NET_RANDOM_ETHADDR=y
CONFIG_SPL_DM_SEQ_ALIAS=y
CONFIG_DFU_MMC=y
CONFIG_DFU_RAM=y
CONFIG_MMC_SDHCI=y
CONFIG_MMC_SDHCI_ZYNQ=y
CONFIG_SPI_FLASH=y
CONFIG_SPI_FLASH_BAR=y
CONFIG_SPI_FLASH_SPANSION=y
CONFIG_SPI_FLASH_STMICRO=y
CONFIG_SPI_FLASH_WINBOND=y
CONFIG_ZYNQ_GEM=y
CONFIG_DEBUG_UART_ZYNQ=y
CONFIG_DEBUG_UART_BASE=0xe0001000
CONFIG_DEBUG_UART_CLOCK=50000000
CONFIG_ZYNQ_QSPI=y
CONFIG_USB=y
CONFIG_USB_EHCI_HCD=y
CONFIG_USB_ULPI_VIEWPORT=y
CONFIG_USB_ULPI=y
CONFIG_USB_STORAGE=y
CONFIG_USB_GADGET=y
CONFIG_CI_UDC=y
CONFIG_USB_GADGET_DOWNLOAD=y
CONFIG_G_DNL_MANUFACTURER="Xilinx"
CONFIG_G_DNL_VENDOR_NUM=0x03FD
CONFIG_G_DNL_PRODUCT_NUM=0x0300

View file

@ -10,217 +10,616 @@
#include <linux/bitops.h>
#include <clk-uclass.h>
#include <clk.h>
#include <asm/arch/sys_proto.h>
#include <dm.h>
#define ZYNQMP_GEM0_REF_CTRL 0xFF5E0050
#define ZYNQMP_IOPLL_CTRL 0xFF5E0020
#define ZYNQMP_RPLL_CTRL 0xFF5E0030
#define ZYNQMP_DPLL_CTRL 0xFD1A002C
#define ZYNQMP_SIP_SVC_MMIO_WRITE 0xC2000013
#define ZYNQMP_SIP_SVC_MMIO_WRITE 0xC2000013
#define ZYNQMP_SIP_SVC_MMIO_WRITE 0xC2000013
#define ZYNQMP_SIP_SVC_MMIO_READ 0xC2000014
#define ZYNQMP_DIV_MAX_VAL 0x3F
#define ZYNQMP_DIV1_SHFT 8
#define ZYNQMP_DIV1_SHFT 8
#define ZYNQMP_DIV2_SHFT 16
#define ZYNQMP_DIV_MASK 0x3F
#define ZYNQMP_PLL_CTRL_FBDIV_MASK 0x7F
#define ZYNQMP_PLL_CTRL_FBDIV_SHFT 8
#define ZYNQMP_GEM_REF_CTRL_SRC_MASK 0x7
#define ZYNQMP_GEM0_CLK_ID 45
#define ZYNQMP_GEM1_CLK_ID 46
#define ZYNQMP_GEM2_CLK_ID 47
#define ZYNQMP_GEM3_CLK_ID 48
DECLARE_GLOBAL_DATA_PTR;
static unsigned long pss_ref_clk;
static const resource_size_t zynqmp_crf_apb_clkc_base = 0xfd1a0020;
static const resource_size_t zynqmp_crl_apb_clkc_base = 0xff5e0020;
static int zynqmp_calculate_divisors(unsigned long req_rate,
unsigned long parent_rate,
u32 *div1, u32 *div2)
/* Full power domain clocks */
#define CRF_APB_APLL_CTRL (zynqmp_crf_apb_clkc_base + 0x00)
#define CRF_APB_DPLL_CTRL (zynqmp_crf_apb_clkc_base + 0x0c)
#define CRF_APB_VPLL_CTRL (zynqmp_crf_apb_clkc_base + 0x18)
#define CRF_APB_PLL_STATUS (zynqmp_crf_apb_clkc_base + 0x24)
#define CRF_APB_APLL_TO_LPD_CTRL (zynqmp_crf_apb_clkc_base + 0x28)
#define CRF_APB_DPLL_TO_LPD_CTRL (zynqmp_crf_apb_clkc_base + 0x2c)
#define CRF_APB_VPLL_TO_LPD_CTRL (zynqmp_crf_apb_clkc_base + 0x30)
/* Peripheral clocks */
#define CRF_APB_ACPU_CTRL (zynqmp_crf_apb_clkc_base + 0x40)
#define CRF_APB_DBG_TRACE_CTRL (zynqmp_crf_apb_clkc_base + 0x44)
#define CRF_APB_DBG_FPD_CTRL (zynqmp_crf_apb_clkc_base + 0x48)
#define CRF_APB_DP_VIDEO_REF_CTRL (zynqmp_crf_apb_clkc_base + 0x50)
#define CRF_APB_DP_AUDIO_REF_CTRL (zynqmp_crf_apb_clkc_base + 0x54)
#define CRF_APB_DP_STC_REF_CTRL (zynqmp_crf_apb_clkc_base + 0x5c)
#define CRF_APB_DDR_CTRL (zynqmp_crf_apb_clkc_base + 0x60)
#define CRF_APB_GPU_REF_CTRL (zynqmp_crf_apb_clkc_base + 0x64)
#define CRF_APB_SATA_REF_CTRL (zynqmp_crf_apb_clkc_base + 0x80)
#define CRF_APB_PCIE_REF_CTRL (zynqmp_crf_apb_clkc_base + 0x94)
#define CRF_APB_GDMA_REF_CTRL (zynqmp_crf_apb_clkc_base + 0x98)
#define CRF_APB_DPDMA_REF_CTRL (zynqmp_crf_apb_clkc_base + 0x9c)
#define CRF_APB_TOPSW_MAIN_CTRL (zynqmp_crf_apb_clkc_base + 0xa0)
#define CRF_APB_TOPSW_LSBUS_CTRL (zynqmp_crf_apb_clkc_base + 0xa4)
#define CRF_APB_GTGREF0_REF_CTRL (zynqmp_crf_apb_clkc_base + 0xa8)
#define CRF_APB_DBG_TSTMP_CTRL (zynqmp_crf_apb_clkc_base + 0xd8)
/* Low power domain clocks */
#define CRL_APB_IOPLL_CTRL (zynqmp_crl_apb_clkc_base + 0x00)
#define CRL_APB_RPLL_CTRL (zynqmp_crl_apb_clkc_base + 0x10)
#define CRL_APB_PLL_STATUS (zynqmp_crl_apb_clkc_base + 0x20)
#define CRL_APB_IOPLL_TO_FPD_CTRL (zynqmp_crl_apb_clkc_base + 0x24)
#define CRL_APB_RPLL_TO_FPD_CTRL (zynqmp_crl_apb_clkc_base + 0x28)
/* Peripheral clocks */
#define CRL_APB_USB3_DUAL_REF_CTRL (zynqmp_crl_apb_clkc_base + 0x2c)
#define CRL_APB_GEM0_REF_CTRL (zynqmp_crl_apb_clkc_base + 0x30)
#define CRL_APB_GEM1_REF_CTRL (zynqmp_crl_apb_clkc_base + 0x34)
#define CRL_APB_GEM2_REF_CTRL (zynqmp_crl_apb_clkc_base + 0x38)
#define CRL_APB_GEM3_REF_CTRL (zynqmp_crl_apb_clkc_base + 0x3c)
#define CRL_APB_USB0_BUS_REF_CTRL (zynqmp_crl_apb_clkc_base + 0x40)
#define CRL_APB_USB1_BUS_REF_CTRL (zynqmp_crl_apb_clkc_base + 0x44)
#define CRL_APB_QSPI_REF_CTRL (zynqmp_crl_apb_clkc_base + 0x48)
#define CRL_APB_SDIO0_REF_CTRL (zynqmp_crl_apb_clkc_base + 0x4c)
#define CRL_APB_SDIO1_REF_CTRL (zynqmp_crl_apb_clkc_base + 0x50)
#define CRL_APB_UART0_REF_CTRL (zynqmp_crl_apb_clkc_base + 0x54)
#define CRL_APB_UART1_REF_CTRL (zynqmp_crl_apb_clkc_base + 0x58)
#define CRL_APB_SPI0_REF_CTRL (zynqmp_crl_apb_clkc_base + 0x5c)
#define CRL_APB_SPI1_REF_CTRL (zynqmp_crl_apb_clkc_base + 0x60)
#define CRL_APB_CAN0_REF_CTRL (zynqmp_crl_apb_clkc_base + 0x64)
#define CRL_APB_CAN1_REF_CTRL (zynqmp_crl_apb_clkc_base + 0x68)
#define CRL_APB_CPU_R5_CTRL (zynqmp_crl_apb_clkc_base + 0x70)
#define CRL_APB_IOU_SWITCH_CTRL (zynqmp_crl_apb_clkc_base + 0x7c)
#define CRL_APB_CSU_PLL_CTRL (zynqmp_crl_apb_clkc_base + 0x80)
#define CRL_APB_PCAP_CTRL (zynqmp_crl_apb_clkc_base + 0x84)
#define CRL_APB_LPD_SWITCH_CTRL (zynqmp_crl_apb_clkc_base + 0x88)
#define CRL_APB_LPD_LSBUS_CTRL (zynqmp_crl_apb_clkc_base + 0x8c)
#define CRL_APB_DBG_LPD_CTRL (zynqmp_crl_apb_clkc_base + 0x90)
#define CRL_APB_NAND_REF_CTRL (zynqmp_crl_apb_clkc_base + 0x94)
#define CRL_APB_ADMA_REF_CTRL (zynqmp_crl_apb_clkc_base + 0x98)
#define CRL_APB_PL0_REF_CTRL (zynqmp_crl_apb_clkc_base + 0xa0)
#define CRL_APB_PL1_REF_CTRL (zynqmp_crl_apb_clkc_base + 0xa4)
#define CRL_APB_PL2_REF_CTRL (zynqmp_crl_apb_clkc_base + 0xa8)
#define CRL_APB_PL3_REF_CTRL (zynqmp_crl_apb_clkc_base + 0xac)
#define CRL_APB_PL0_THR_CNT (zynqmp_crl_apb_clkc_base + 0xb4)
#define CRL_APB_PL1_THR_CNT (zynqmp_crl_apb_clkc_base + 0xbc)
#define CRL_APB_PL2_THR_CNT (zynqmp_crl_apb_clkc_base + 0xc4)
#define CRL_APB_PL3_THR_CNT (zynqmp_crl_apb_clkc_base + 0xdc)
#define CRL_APB_GEM_TSU_REF_CTRL (zynqmp_crl_apb_clkc_base + 0xe0)
#define CRL_APB_DLL_REF_CTRL (zynqmp_crl_apb_clkc_base + 0xe4)
#define CRL_APB_AMS_REF_CTRL (zynqmp_crl_apb_clkc_base + 0xe8)
#define CRL_APB_I2C0_REF_CTRL (zynqmp_crl_apb_clkc_base + 0x100)
#define CRL_APB_I2C1_REF_CTRL (zynqmp_crl_apb_clkc_base + 0x104)
#define CRL_APB_TIMESTAMP_REF_CTRL (zynqmp_crl_apb_clkc_base + 0x108)
#define ZYNQ_CLK_MAXDIV 0x3f
#define CLK_CTRL_DIV1_SHIFT 16
#define CLK_CTRL_DIV1_MASK (ZYNQ_CLK_MAXDIV << CLK_CTRL_DIV1_SHIFT)
#define CLK_CTRL_DIV0_SHIFT 8
#define CLK_CTRL_DIV0_MASK (ZYNQ_CLK_MAXDIV << CLK_CTRL_DIV0_SHIFT)
#define CLK_CTRL_SRCSEL_SHIFT 0
#define CLK_CTRL_SRCSEL_MASK (0x3 << CLK_CTRL_SRCSEL_SHIFT)
#define PLLCTRL_FBDIV_MASK 0x7f00
#define PLLCTRL_FBDIV_SHIFT 8
#define PLLCTRL_RESET_MASK 1
#define PLLCTRL_RESET_SHIFT 0
#define PLLCTRL_BYPASS_MASK 0x8
#define PLLCTRL_BYPASS_SHFT 3
#define PLLCTRL_POST_SRC_SHFT 24
#define PLLCTRL_POST_SRC_MASK (0x7 << PLLCTRL_POST_SRC_SHFT)
#define NUM_MIO_PINS 77
enum zynqmp_clk {
iopll, rpll,
apll, dpll, vpll,
iopll_to_fpd, rpll_to_fpd, apll_to_lpd, dpll_to_lpd, vpll_to_lpd,
acpu, acpu_half,
dbg_fpd, dbg_lpd, dbg_trace, dbg_tstmp,
dp_video_ref, dp_audio_ref,
dp_stc_ref, gdma_ref, dpdma_ref,
ddr_ref, sata_ref, pcie_ref,
gpu_ref, gpu_pp0_ref, gpu_pp1_ref,
topsw_main, topsw_lsbus,
gtgref0_ref,
lpd_switch, lpd_lsbus,
usb0_bus_ref, usb1_bus_ref, usb3_dual_ref, usb0, usb1,
cpu_r5, cpu_r5_core,
csu_spb, csu_pll, pcap,
iou_switch,
gem_tsu_ref, gem_tsu,
gem0_ref, gem1_ref, gem2_ref, gem3_ref,
gem0_rx, gem1_rx, gem2_rx, gem3_rx,
qspi_ref,
sdio0_ref, sdio1_ref,
uart0_ref, uart1_ref,
spi0_ref, spi1_ref,
nand_ref,
i2c0_ref, i2c1_ref, can0_ref, can1_ref, can0, can1,
dll_ref,
adma_ref,
timestamp_ref,
ams_ref,
pl0, pl1, pl2, pl3,
wdt,
clk_max,
};
static const char * const clk_names[clk_max] = {
"iopll", "rpll", "apll", "dpll",
"vpll", "iopll_to_fpd", "rpll_to_fpd",
"apll_to_lpd", "dpll_to_lpd", "vpll_to_lpd",
"acpu", "acpu_half", "dbf_fpd", "dbf_lpd",
"dbg_trace", "dbg_tstmp", "dp_video_ref",
"dp_audio_ref", "dp_stc_ref", "gdma_ref",
"dpdma_ref", "ddr_ref", "sata_ref", "pcie_ref",
"gpu_ref", "gpu_pp0_ref", "gpu_pp1_ref",
"topsw_main", "topsw_lsbus", "gtgref0_ref",
"lpd_switch", "lpd_lsbus", "usb0_bus_ref",
"usb1_bus_ref", "usb3_dual_ref", "usb0",
"usb1", "cpu_r5", "cpu_r5_core", "csu_spb",
"csu_pll", "pcap", "iou_switch", "gem_tsu_ref",
"gem_tsu", "gem0_ref", "gem1_ref", "gem2_ref",
"gem3_ref", "gem0_tx", "gem1_tx", "gem2_tx",
"gem3_tx", "qspi_ref", "sdio0_ref", "sdio1_ref",
"uart0_ref", "uart1_ref", "spi0_ref",
"spi1_ref", "nand_ref", "i2c0_ref", "i2c1_ref",
"can0_ref", "can1_ref", "can0", "can1",
"dll_ref", "adma_ref", "timestamp_ref",
"ams_ref", "pl0", "pl1", "pl2", "pl3", "wdt"
};
struct zynqmp_clk_priv {
unsigned long ps_clk_freq;
unsigned long video_clk;
unsigned long pss_alt_ref_clk;
unsigned long gt_crx_ref_clk;
unsigned long aux_ref_clk;
};
static u32 zynqmp_clk_get_register(enum zynqmp_clk id)
{
u32 req_div = 1;
u32 i;
switch (id) {
case iopll:
return CRL_APB_IOPLL_CTRL;
case rpll:
return CRL_APB_RPLL_CTRL;
case apll:
return CRF_APB_APLL_CTRL;
case dpll:
return CRF_APB_DPLL_CTRL;
case vpll:
return CRF_APB_VPLL_CTRL;
case acpu:
return CRF_APB_ACPU_CTRL;
case ddr_ref:
return CRF_APB_DDR_CTRL;
case qspi_ref:
return CRL_APB_QSPI_REF_CTRL;
case gem0_ref:
return CRL_APB_GEM0_REF_CTRL;
case gem1_ref:
return CRL_APB_GEM1_REF_CTRL;
case gem2_ref:
return CRL_APB_GEM2_REF_CTRL;
case gem3_ref:
return CRL_APB_GEM3_REF_CTRL;
case uart0_ref:
return CRL_APB_UART0_REF_CTRL;
case uart1_ref:
return CRL_APB_UART1_REF_CTRL;
case sdio0_ref:
return CRL_APB_SDIO0_REF_CTRL;
case sdio1_ref:
return CRL_APB_SDIO1_REF_CTRL;
case spi0_ref:
return CRL_APB_SPI0_REF_CTRL;
case spi1_ref:
return CRL_APB_SPI1_REF_CTRL;
case nand_ref:
return CRL_APB_NAND_REF_CTRL;
case i2c0_ref:
return CRL_APB_I2C0_REF_CTRL;
case i2c1_ref:
return CRL_APB_I2C1_REF_CTRL;
case can0_ref:
return CRL_APB_CAN0_REF_CTRL;
case can1_ref:
return CRL_APB_CAN1_REF_CTRL;
default:
debug("Invalid clk id%d\n", id);
}
return 0;
}
/*
* calculate two divisors to get
* required rate and each divisor
* should be less than 63
*/
req_div = DIV_ROUND_UP(parent_rate, req_rate);
static enum zynqmp_clk zynqmp_clk_get_cpu_pll(u32 clk_ctrl)
{
u32 srcsel = (clk_ctrl & CLK_CTRL_SRCSEL_MASK) >>
CLK_CTRL_SRCSEL_SHIFT;
for (i = 1; i <= req_div; i++) {
if ((req_div % i) == 0) {
*div1 = req_div / i;
*div2 = i;
if ((*div1 < ZYNQMP_DIV_MAX_VAL) &&
(*div2 < ZYNQMP_DIV_MAX_VAL))
return 0;
switch (srcsel) {
case 2:
return dpll;
case 3:
return vpll;
case 0 ... 1:
default:
return apll;
}
}
static enum zynqmp_clk zynqmp_clk_get_ddr_pll(u32 clk_ctrl)
{
u32 srcsel = (clk_ctrl & CLK_CTRL_SRCSEL_MASK) >>
CLK_CTRL_SRCSEL_SHIFT;
switch (srcsel) {
case 1:
return vpll;
case 0:
default:
return dpll;
}
}
static enum zynqmp_clk zynqmp_clk_get_peripheral_pll(u32 clk_ctrl)
{
u32 srcsel = (clk_ctrl & CLK_CTRL_SRCSEL_MASK) >>
CLK_CTRL_SRCSEL_SHIFT;
switch (srcsel) {
case 2:
return rpll;
case 3:
return dpll;
case 0 ... 1:
default:
return iopll;
}
}
static ulong zynqmp_clk_get_pll_src(ulong clk_ctrl,
struct zynqmp_clk_priv *priv,
bool is_pre_src)
{
u32 src_sel;
if (is_pre_src)
src_sel = (clk_ctrl & PLLCTRL_POST_SRC_MASK) >>
PLLCTRL_POST_SRC_SHFT;
else
src_sel = (clk_ctrl & PLLCTRL_POST_SRC_MASK) >>
PLLCTRL_POST_SRC_SHFT;
switch (src_sel) {
case 4:
return priv->video_clk;
case 5:
return priv->pss_alt_ref_clk;
case 6:
return priv->aux_ref_clk;
case 7:
return priv->gt_crx_ref_clk;
case 0 ... 3:
default:
return priv->ps_clk_freq;
}
}
static ulong zynqmp_clk_get_pll_rate(struct zynqmp_clk_priv *priv,
enum zynqmp_clk id)
{
u32 clk_ctrl, reset, mul;
ulong freq;
int ret;
ret = zynqmp_mmio_read(zynqmp_clk_get_register(id), &clk_ctrl);
if (ret) {
printf("%s mio read fail\n", __func__);
return -EIO;
}
if (clk_ctrl & PLLCTRL_BYPASS_MASK)
freq = zynqmp_clk_get_pll_src(clk_ctrl, priv, 0);
else
freq = zynqmp_clk_get_pll_src(clk_ctrl, priv, 1);
reset = (clk_ctrl & PLLCTRL_RESET_MASK) >> PLLCTRL_RESET_SHIFT;
if (reset && !(clk_ctrl & PLLCTRL_BYPASS_MASK))
return 0;
mul = (clk_ctrl & PLLCTRL_FBDIV_MASK) >> PLLCTRL_FBDIV_SHIFT;
freq *= mul;
if (clk_ctrl & (1 << 16))
freq /= 2;
return freq;
}
static ulong zynqmp_clk_get_cpu_rate(struct zynqmp_clk_priv *priv,
enum zynqmp_clk id)
{
u32 clk_ctrl, div;
enum zynqmp_clk pll;
int ret;
unsigned long pllrate;
ret = zynqmp_mmio_read(CRF_APB_ACPU_CTRL, &clk_ctrl);
if (ret) {
printf("%s mio read fail\n", __func__);
return -EIO;
}
div = (clk_ctrl & CLK_CTRL_DIV0_MASK) >> CLK_CTRL_DIV0_SHIFT;
pll = zynqmp_clk_get_cpu_pll(clk_ctrl);
pllrate = zynqmp_clk_get_pll_rate(priv, pll);
if (IS_ERR_VALUE(pllrate))
return pllrate;
return DIV_ROUND_CLOSEST(pllrate, div);
}
static ulong zynqmp_clk_get_ddr_rate(struct zynqmp_clk_priv *priv)
{
u32 clk_ctrl, div;
enum zynqmp_clk pll;
int ret;
ulong pllrate;
ret = zynqmp_mmio_read(CRF_APB_DDR_CTRL, &clk_ctrl);
if (ret) {
printf("%s mio read fail\n", __func__);
return -EIO;
}
div = (clk_ctrl & CLK_CTRL_DIV0_MASK) >> CLK_CTRL_DIV0_SHIFT;
pll = zynqmp_clk_get_ddr_pll(clk_ctrl);
pllrate = zynqmp_clk_get_pll_rate(priv, pll);
if (IS_ERR_VALUE(pllrate))
return pllrate;
return DIV_ROUND_CLOSEST(pllrate, div);
}
static ulong zynqmp_clk_get_peripheral_rate(struct zynqmp_clk_priv *priv,
enum zynqmp_clk id, bool two_divs)
{
enum zynqmp_clk pll;
u32 clk_ctrl, div0;
u32 div1 = 1;
int ret;
ulong pllrate;
ret = zynqmp_mmio_read(zynqmp_clk_get_register(id), &clk_ctrl);
if (ret) {
printf("%s mio read fail\n", __func__);
return -EIO;
}
div0 = (clk_ctrl & CLK_CTRL_DIV0_MASK) >> CLK_CTRL_DIV0_SHIFT;
if (!div0)
div0 = 1;
if (two_divs) {
div1 = (clk_ctrl & CLK_CTRL_DIV1_MASK) >> CLK_CTRL_DIV1_SHIFT;
if (!div1)
div1 = 1;
}
pll = zynqmp_clk_get_peripheral_pll(clk_ctrl);
pllrate = zynqmp_clk_get_pll_rate(priv, pll);
if (IS_ERR_VALUE(pllrate))
return pllrate;
return
DIV_ROUND_CLOSEST(
DIV_ROUND_CLOSEST(pllrate, div0), div1);
}
static unsigned long zynqmp_clk_calc_peripheral_two_divs(ulong rate,
ulong pll_rate,
u32 *div0, u32 *div1)
{
long new_err, best_err = (long)(~0UL >> 1);
ulong new_rate, best_rate = 0;
u32 d0, d1;
for (d0 = 1; d0 <= ZYNQ_CLK_MAXDIV; d0++) {
for (d1 = 1; d1 <= ZYNQ_CLK_MAXDIV >> 1; d1++) {
new_rate = DIV_ROUND_CLOSEST(
DIV_ROUND_CLOSEST(pll_rate, d0), d1);
new_err = abs(new_rate - rate);
if (new_err < best_err) {
*div0 = d0;
*div1 = d1;
best_err = new_err;
best_rate = new_rate;
}
}
}
return -1;
return best_rate;
}
static int zynqmp_get_periph_id(unsigned long id)
static ulong zynqmp_clk_set_peripheral_rate(struct zynqmp_clk_priv *priv,
enum zynqmp_clk id, ulong rate,
bool two_divs)
{
int periph_id;
enum zynqmp_clk pll;
u32 clk_ctrl, div0 = 0, div1 = 0;
ulong pll_rate, new_rate;
u32 reg;
int ret;
u32 mask;
reg = zynqmp_clk_get_register(id);
ret = zynqmp_mmio_read(reg, &clk_ctrl);
if (ret) {
printf("%s mio read fail\n", __func__);
return -EIO;
}
pll = zynqmp_clk_get_peripheral_pll(clk_ctrl);
pll_rate = zynqmp_clk_get_pll_rate(priv, pll);
if (IS_ERR_VALUE(pll_rate))
return pll_rate;
clk_ctrl &= ~CLK_CTRL_DIV0_MASK;
if (two_divs) {
clk_ctrl &= ~CLK_CTRL_DIV1_MASK;
new_rate = zynqmp_clk_calc_peripheral_two_divs(rate, pll_rate,
&div0, &div1);
clk_ctrl |= div1 << CLK_CTRL_DIV1_SHIFT;
} else {
div0 = DIV_ROUND_CLOSEST(pll_rate, rate);
if (div0 > ZYNQ_CLK_MAXDIV)
div0 = ZYNQ_CLK_MAXDIV;
new_rate = DIV_ROUND_CLOSEST(rate, div0);
}
clk_ctrl |= div0 << CLK_CTRL_DIV0_SHIFT;
mask = (ZYNQ_CLK_MAXDIV << CLK_CTRL_DIV0_SHIFT) |
(ZYNQ_CLK_MAXDIV << CLK_CTRL_DIV1_SHIFT);
ret = zynqmp_mmio_write(reg, mask, clk_ctrl);
if (ret) {
printf("%s mio write fail\n", __func__);
return -EIO;
}
return new_rate;
}
static ulong zynqmp_clk_get_rate(struct clk *clk)
{
struct zynqmp_clk_priv *priv = dev_get_priv(clk->dev);
enum zynqmp_clk id = clk->id;
bool two_divs = false;
switch (id) {
case ZYNQMP_GEM0_CLK_ID:
periph_id = 0;
break;
case ZYNQMP_GEM1_CLK_ID:
periph_id = 1;
break;
case ZYNQMP_GEM2_CLK_ID:
periph_id = 2;
break;
case ZYNQMP_GEM3_CLK_ID:
periph_id = 3;
break;
case iopll ... vpll:
return zynqmp_clk_get_pll_rate(priv, id);
case acpu:
return zynqmp_clk_get_cpu_rate(priv, id);
case ddr_ref:
return zynqmp_clk_get_ddr_rate(priv);
case gem0_ref ... gem3_ref:
case qspi_ref ... can1_ref:
two_divs = true;
return zynqmp_clk_get_peripheral_rate(priv, id, two_divs);
default:
printf("%s, Invalid clock id:%ld\n", __func__, id);
return -EINVAL;
return -ENXIO;
}
return periph_id;
}
static int zynqmp_set_clk(unsigned long id, u32 div1, u32 div2)
static ulong zynqmp_clk_set_rate(struct clk *clk, ulong rate)
{
struct pt_regs regs;
ulong reg;
u32 mask, value;
struct zynqmp_clk_priv *priv = dev_get_priv(clk->dev);
enum zynqmp_clk id = clk->id;
bool two_divs = true;
id = zynqmp_get_periph_id(id);
if (id < 0)
return -EINVAL;
reg = (ulong)((u32 *)ZYNQMP_GEM0_REF_CTRL + id);
mask = (ZYNQMP_DIV_MASK << ZYNQMP_DIV1_SHFT) |
(ZYNQMP_DIV_MASK << ZYNQMP_DIV2_SHFT);
value = (div1 << ZYNQMP_DIV1_SHFT) | (div2 << ZYNQMP_DIV2_SHFT);
debug("%s: reg:0x%lx, mask:0x%x, value:0x%x\n", __func__, reg, mask,
value);
regs.regs[0] = ZYNQMP_SIP_SVC_MMIO_WRITE;
regs.regs[1] = ((u64)mask << 32) | reg;
regs.regs[2] = value;
regs.regs[3] = 0;
smc_call(&regs);
return regs.regs[0];
}
static unsigned long zynqmp_clk_get_rate(struct clk *clk)
{
struct pt_regs regs;
ulong reg;
unsigned long value;
int id;
id = zynqmp_get_periph_id(clk->id);
if (id < 0)
return -EINVAL;
reg = (ulong)((u32 *)ZYNQMP_GEM0_REF_CTRL + id);
regs.regs[0] = ZYNQMP_SIP_SVC_MMIO_READ;
regs.regs[1] = reg;
regs.regs[2] = 0;
regs.regs[3] = 0;
smc_call(&regs);
value = upper_32_bits(regs.regs[0]);
value &= ZYNQMP_GEM_REF_CTRL_SRC_MASK;
switch (value) {
case 0:
regs.regs[1] = ZYNQMP_IOPLL_CTRL;
break;
case 2:
regs.regs[1] = ZYNQMP_RPLL_CTRL;
break;
case 3:
regs.regs[1] = ZYNQMP_DPLL_CTRL;
break;
switch (id) {
case gem0_ref ... gem3_ref:
case qspi_ref ... can1_ref:
return zynqmp_clk_set_peripheral_rate(priv, id,
rate, two_divs);
default:
return -EINVAL;
return -ENXIO;
}
regs.regs[0] = ZYNQMP_SIP_SVC_MMIO_READ;
regs.regs[2] = 0;
regs.regs[3] = 0;
smc_call(&regs);
value = upper_32_bits(regs.regs[0]) &
(ZYNQMP_PLL_CTRL_FBDIV_MASK <<
ZYNQMP_PLL_CTRL_FBDIV_SHFT);
value >>= ZYNQMP_PLL_CTRL_FBDIV_SHFT;
value *= pss_ref_clk;
return value;
}
static ulong zynqmp_clk_set_rate(struct clk *clk, unsigned long clk_rate)
int soc_clk_dump(void)
{
int ret;
u32 div1 = 0;
u32 div2 = 0;
unsigned long input_clk;
struct udevice *dev;
int i, ret;
input_clk = zynqmp_clk_get_rate(clk);
if (IS_ERR_VALUE(input_clk)) {
dev_err(dev, "failed to get input_clk\n");
return -EINVAL;
}
ret = uclass_get_device_by_driver(UCLASS_CLK,
DM_GET_DRIVER(zynqmp_clk), &dev);
if (ret)
return ret;
debug("%s: i/p CLK %ld, clk_rate:0x%ld\n", __func__, input_clk,
clk_rate);
printf("clk\t\tfrequency\n");
for (i = 0; i < clk_max; i++) {
const char *name = clk_names[i];
if (name) {
struct clk clk;
unsigned long rate;
ret = zynqmp_calculate_divisors(clk_rate, input_clk, &div1, &div2);
if (ret) {
dev_err(dev, "failed to proper divisors\n");
return -EINVAL;
}
clk.id = i;
ret = clk_request(dev, &clk);
if (ret < 0)
return ret;
debug("%s: Div1:%d, Div2:%d\n", __func__, div1, div2);
rate = clk_get_rate(&clk);
ret = zynqmp_set_clk(clk->id, div1, div2);
if (ret) {
dev_err(dev, "failed to set gem clk\n");
return -EINVAL;
clk_free(&clk);
if ((rate == (unsigned long)-ENOSYS) ||
(rate == (unsigned long)-ENXIO) ||
(rate == (unsigned long)-EIO))
printf("%10s%20s\n", name, "unknown");
else
printf("%10s%20lu\n", name, rate);
}
}
return 0;
}
static int zynqmp_clk_probe(struct udevice *dev)
static int zynqmp_get_freq_by_name(char *name, struct udevice *dev, ulong *freq)
{
struct clk clk;
int ret;
debug("%s\n", __func__);
ret = clk_get_by_name(dev, "pss_ref_clk", &clk);
ret = clk_get_by_name(dev, name, &clk);
if (ret < 0) {
dev_err(dev, "failed to get pss_ref_clk\n");
dev_err(dev, "failed to get %s\n", name);
return ret;
}
pss_ref_clk = clk_get_rate(&clk);
if (IS_ERR_VALUE(pss_ref_clk)) {
dev_err(dev, "failed to get rate pss_ref_clk\n");
*freq = clk_get_rate(&clk);
if (IS_ERR_VALUE(*freq)) {
dev_err(dev, "failed to get rate %s\n", name);
return -EINVAL;
}
return 0;
}
static int zynqmp_clk_probe(struct udevice *dev)
{
int ret;
struct zynqmp_clk_priv *priv = dev_get_priv(dev);
debug("%s\n", __func__);
ret = zynqmp_get_freq_by_name("pss_ref_clk", dev, &priv->ps_clk_freq);
if (ret < 0)
return -EINVAL;
ret = zynqmp_get_freq_by_name("video_clk", dev, &priv->video_clk);
if (ret < 0)
return -EINVAL;
ret = zynqmp_get_freq_by_name("pss_alt_ref_clk", dev,
&priv->pss_alt_ref_clk);
if (ret < 0)
return -EINVAL;
ret = zynqmp_get_freq_by_name("aux_ref_clk", dev, &priv->aux_ref_clk);
if (ret < 0)
return -EINVAL;
ret = zynqmp_get_freq_by_name("gt_crx_ref_clk", dev,
&priv->gt_crx_ref_clk);
if (ret < 0)
return -EINVAL;
return 0;
}
static struct clk_ops zynqmp_clk_ops = {
.set_rate = zynqmp_clk_set_rate,
@ -238,4 +637,5 @@ U_BOOT_DRIVER(zynqmp_clk) = {
.of_match = zynqmp_clk_ids,
.probe = zynqmp_clk_probe,
.ops = &zynqmp_clk_ops,
.priv_auto_alloc_size = sizeof(struct zynqmp_clk_priv),
};

View file

@ -29,7 +29,6 @@ int fpga_loadbitstream(int devnum, char *fpgadata, size_t size,
{
unsigned int length;
unsigned int swapsize;
char buffer[80];
unsigned char *dataptr;
unsigned int i;
const fpga_desc *desc;
@ -57,10 +56,8 @@ int fpga_loadbitstream(int devnum, char *fpgadata, size_t size,
length = (*dataptr << 8) + *(dataptr + 1);
dataptr += 2;
for (i = 0; i < length; i++)
buffer[i] = *dataptr++;
printf(" design filename = \"%s\"\n", buffer);
printf(" design filename = \"%s\"\n", dataptr);
dataptr += length;
/* get part number (identifier, length, string) */
if (*dataptr++ != 0x62) {
@ -71,23 +68,22 @@ int fpga_loadbitstream(int devnum, char *fpgadata, size_t size,
length = (*dataptr << 8) + *(dataptr + 1);
dataptr += 2;
for (i = 0; i < length; i++)
buffer[i] = *dataptr++;
if (xdesc->name) {
i = (ulong)strstr(buffer, xdesc->name);
i = (ulong)strstr((char *)dataptr, xdesc->name);
if (!i) {
printf("%s: Wrong bitstream ID for this device\n",
__func__);
printf("%s: Bitstream ID %s, current device ID %d/%s\n",
__func__, buffer, devnum, xdesc->name);
__func__, dataptr, devnum, xdesc->name);
return FPGA_FAIL;
}
} else {
printf("%s: Please fill correct device ID to xilinx_desc\n",
__func__);
}
printf(" part number = \"%s\"\n", buffer);
printf(" part number = \"%s\"\n", dataptr);
dataptr += length;
/* get date (identifier, length, string) */
if (*dataptr++ != 0x63) {
@ -98,9 +94,8 @@ int fpga_loadbitstream(int devnum, char *fpgadata, size_t size,
length = (*dataptr << 8) + *(dataptr+1);
dataptr += 2;
for (i = 0; i < length; i++)
buffer[i] = *dataptr++;
printf(" date = \"%s\"\n", buffer);
printf(" date = \"%s\"\n", dataptr);
dataptr += length;
/* get time (identifier, length, string) */
if (*dataptr++ != 0x64) {
@ -111,9 +106,8 @@ int fpga_loadbitstream(int devnum, char *fpgadata, size_t size,
length = (*dataptr << 8) + *(dataptr+1);
dataptr += 2;
for (i = 0; i < length; i++)
buffer[i] = *dataptr++;
printf(" time = \"%s\"\n", buffer);
printf(" time = \"%s\"\n", dataptr);
dataptr += length;
/* get fpga data length (identifier, length) */
if (*dataptr++ != 0x65) {

View file

@ -286,6 +286,7 @@ void board_show_dram(phys_size_t size);
*/
int arch_fixup_fdt(void *blob);
int reserve_mmu(void);
/* common/flash.c */
void flash_perror (int);

View file

@ -171,6 +171,50 @@
/* enable preboot to be loaded before CONFIG_BOOTDELAY */
#define CONFIG_PREBOOT
/* Boot configuration */
#define CONFIG_BOOTCOMMAND "run $modeboot || run distro_bootcmd"
#define CONFIG_SYS_LOAD_ADDR 0 /* default? */
/* Distro boot enablement */
#ifdef CONFIG_SPL_BUILD
#define BOOTENV
#else
#include <config_distro_defaults.h>
#ifdef CONFIG_CMD_MMC
#define BOOT_TARGET_DEVICES_MMC(func) func(MMC, mmc, 0)
#else
#define BOOT_TARGET_DEVICES_MMC(func)
#endif
#ifdef CONFIG_CMD_USB
#define BOOT_TARGET_DEVICES_USB(func) func(USB, usb, 0)
#else
#define BOOT_TARGET_DEVICES_USB(func)
#endif
#if defined(CONFIG_CMD_PXE)
#define BOOT_TARGET_DEVICES_PXE(func) func(PXE, pxe, na)
#else
#define BOOT_TARGET_DEVICES_PXE(func)
#endif
#if defined(CONFIG_CMD_DHCP)
#define BOOT_TARGET_DEVICES_DHCP(func) func(DHCP, dhcp, na)
#else
#define BOOT_TARGET_DEVICES_DHCP(func)
#endif
#define BOOT_TARGET_DEVICES(func) \
BOOT_TARGET_DEVICES_MMC(func) \
BOOT_TARGET_DEVICES_USB(func) \
BOOT_TARGET_DEVICES_PXE(func) \
BOOT_TARGET_DEVICES_DHCP(func)
#include <config_distro_bootcmd.h>
#endif /* CONFIG_SPL_BUILD */
/* Default environment */
#ifndef CONFIG_EXTRA_ENV_SETTINGS
#define CONFIG_EXTRA_ENV_SETTINGS \
@ -182,6 +226,11 @@
"fdt_high=0x20000000\0" \
"initrd_high=0x20000000\0" \
"loadbootenv_addr=0x2000000\0" \
"fdt_addr_r=0x1f00000\0" \
"pxefile_addr_r=0x2000000\0" \
"kernel_addr_r=0x2000000\0" \
"scriptaddr=0x3000000\0" \
"ramdisk_addr_r=0x3100000\0" \
"bootenv=uEnv.txt\0" \
"bootenv_dev=mmc\0" \
"loadbootenv=load ${bootenv_dev} 0 ${loadbootenv_addr} ${bootenv}\0" \
@ -217,12 +266,10 @@
"echo Copying FIT from USB to RAM... && " \
"load usb 0 ${load_addr} ${fit_image} && " \
"bootm ${load_addr}; fi\0" \
DFU_ALT_INFO
DFU_ALT_INFO \
BOOTENV
#endif
#define CONFIG_BOOTCOMMAND "run $modeboot"
#define CONFIG_SYS_LOAD_ADDR 0 /* default? */
/* Miscellaneous configurable options */
#define CONFIG_CMDLINE_EDITING

View file

@ -20,7 +20,7 @@
#define ZYNQMP_CSU_IDCODE_DEVICE_CODE_MASK (0xf << \
ZYNQMP_CSU_IDCODE_DEVICE_CODE_SHIFT)
#define ZYNQMP_CSU_IDCODE_SVD_SHIFT 12
#define ZYNQMP_CSU_IDCODE_SVD_MASK (0xe << ZYNQMP_CSU_IDCODE_SVD_SHIFT)
#define ZYNQMP_CSU_IDCODE_SVD_MASK (0x7 << ZYNQMP_CSU_IDCODE_SVD_SHIFT)
extern struct xilinx_fpga_op zynqmp_op;