- New board: rk3328 NanoPi R2S board;
- Fix init voltage for some rk3399 boards;
- enable rng for rk3399 by default;
- set default to SPI bus 1 for SPI-flash for some board;
- add dwc PCIe controller driver on rockchip platform;
This commit is contained in:
Tom Rini 2021-01-21 07:39:47 -05:00
commit 184aa65041
25 changed files with 1594 additions and 19 deletions

View file

@ -110,6 +110,7 @@ dtb-$(CONFIG_ROCKCHIP_RK3308) += \
dtb-$(CONFIG_ROCKCHIP_RK3328) += \
rk3328-evb.dtb \
rk3328-nanopi-r2s.dtb \
rk3328-roc-cc.dtb \
rk3328-rock64.dtb \
rk3328-rock-pi-e.dtb

View file

@ -0,0 +1,40 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* (C) Copyright 2018-2019 Rockchip Electronics Co., Ltd
* (C) Copyright 2020 David Bauer
*/
#include "rk3328-u-boot.dtsi"
#include "rk3328-sdram-ddr4-666.dtsi"
/ {
chosen {
u-boot,spl-boot-order = "same-as-spl", &sdmmc, &emmc;
};
};
&gpio0 {
u-boot,dm-spl;
};
&pinctrl {
u-boot,dm-spl;
};
&sdmmc0m1_gpio {
u-boot,dm-spl;
};
&pcfg_pull_up_4ma {
u-boot,dm-spl;
};
/* Need this and all the pinctrl/gpio stuff above to set pinmux */
&vcc_sd {
u-boot,dm-spl;
};
&gmac2io {
snps,reset-gpio = <&gpio1 RK_PC2 GPIO_ACTIVE_LOW>;
snps,reset-active-low;
snps,reset-delays-us = <0 10000 50000>;
};

View file

@ -0,0 +1,370 @@
// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
/*
* Copyright (c) 2020 David Bauer <mail@david-bauer.net>
*/
/dts-v1/;
#include <dt-bindings/input/input.h>
#include <dt-bindings/gpio/gpio.h>
#include "rk3328.dtsi"
/ {
model = "FriendlyElec NanoPi R2S";
compatible = "friendlyarm,nanopi-r2s", "rockchip,rk3328";
chosen {
stdout-path = "serial2:1500000n8";
};
gmac_clk: gmac-clock {
compatible = "fixed-clock";
clock-frequency = <125000000>;
clock-output-names = "gmac_clkin";
#clock-cells = <0>;
};
keys {
compatible = "gpio-keys";
pinctrl-0 = <&reset_button_pin>;
pinctrl-names = "default";
reset {
label = "reset";
gpios = <&gpio0 RK_PA0 GPIO_ACTIVE_LOW>;
linux,code = <KEY_RESTART>;
debounce-interval = <50>;
};
};
leds {
compatible = "gpio-leds";
pinctrl-0 = <&lan_led_pin>, <&sys_led_pin>, <&wan_led_pin>;
pinctrl-names = "default";
lan_led: led-0 {
gpios = <&gpio2 RK_PB7 GPIO_ACTIVE_HIGH>;
label = "nanopi-r2s:green:lan";
};
sys_led: led-1 {
gpios = <&gpio0 RK_PA2 GPIO_ACTIVE_HIGH>;
label = "nanopi-r2s:red:sys";
};
wan_led: led-2 {
gpios = <&gpio2 RK_PC2 GPIO_ACTIVE_HIGH>;
label = "nanopi-r2s:green:wan";
};
};
vcc_io_sdio: sdmmcio-regulator {
compatible = "regulator-gpio";
enable-active-high;
gpios = <&gpio1 RK_PD4 GPIO_ACTIVE_HIGH>;
pinctrl-0 = <&sdio_vcc_pin>;
pinctrl-names = "default";
regulator-name = "vcc_io_sdio";
regulator-always-on;
regulator-min-microvolt = <1800000>;
regulator-max-microvolt = <3300000>;
regulator-settling-time-us = <5000>;
regulator-type = "voltage";
startup-delay-us = <2000>;
states = <1800000 0x1
3300000 0x0>;
vin-supply = <&vcc_io_33>;
};
vcc_sd: sdmmc-regulator {
compatible = "regulator-fixed";
gpio = <&gpio0 RK_PD6 GPIO_ACTIVE_LOW>;
pinctrl-0 = <&sdmmc0m1_gpio>;
pinctrl-names = "default";
regulator-name = "vcc_sd";
regulator-boot-on;
regulator-min-microvolt = <3300000>;
regulator-max-microvolt = <3300000>;
vin-supply = <&vcc_io_33>;
};
vdd_5v: vdd-5v {
compatible = "regulator-fixed";
regulator-name = "vdd_5v";
regulator-always-on;
regulator-boot-on;
regulator-min-microvolt = <5000000>;
regulator-max-microvolt = <5000000>;
};
};
&cpu0 {
cpu-supply = <&vdd_arm>;
};
&cpu1 {
cpu-supply = <&vdd_arm>;
};
&cpu2 {
cpu-supply = <&vdd_arm>;
};
&cpu3 {
cpu-supply = <&vdd_arm>;
};
&gmac2io {
assigned-clocks = <&cru SCLK_MAC2IO>, <&cru SCLK_MAC2IO_EXT>;
assigned-clock-parents = <&gmac_clk>, <&gmac_clk>;
clock_in_out = "input";
phy-handle = <&rtl8211e>;
phy-mode = "rgmii";
phy-supply = <&vcc_io_33>;
pinctrl-0 = <&rgmiim1_pins>;
pinctrl-names = "default";
rx_delay = <0x18>;
snps,aal;
tx_delay = <0x24>;
status = "okay";
mdio {
compatible = "snps,dwmac-mdio";
#address-cells = <1>;
#size-cells = <0>;
rtl8211e: ethernet-phy@1 {
compatible = "ethernet-phy-id001c.c915",
"ethernet-phy-ieee802.3-c22";
reg = <1>;
pinctrl-0 = <&eth_phy_reset_pin>;
pinctrl-names = "default";
reset-assert-us = <10000>;
reset-deassert-us = <50000>;
reset-gpios = <&gpio1 RK_PC2 GPIO_ACTIVE_LOW>;
};
};
};
&i2c1 {
status = "okay";
rk805: pmic@18 {
compatible = "rockchip,rk805";
reg = <0x18>;
interrupt-parent = <&gpio1>;
interrupts = <24 IRQ_TYPE_LEVEL_LOW>;
#clock-cells = <1>;
clock-output-names = "xin32k", "rk805-clkout2";
gpio-controller;
#gpio-cells = <2>;
pinctrl-0 = <&pmic_int_l>;
pinctrl-names = "default";
rockchip,system-power-controller;
wakeup-source;
vcc1-supply = <&vdd_5v>;
vcc2-supply = <&vdd_5v>;
vcc3-supply = <&vdd_5v>;
vcc4-supply = <&vdd_5v>;
vcc5-supply = <&vcc_io_33>;
vcc6-supply = <&vdd_5v>;
regulators {
vdd_log: DCDC_REG1 {
regulator-name = "vdd_log";
regulator-always-on;
regulator-boot-on;
regulator-min-microvolt = <712500>;
regulator-max-microvolt = <1450000>;
regulator-ramp-delay = <12500>;
regulator-state-mem {
regulator-on-in-suspend;
regulator-suspend-microvolt = <1000000>;
};
};
vdd_arm: DCDC_REG2 {
regulator-name = "vdd_arm";
regulator-always-on;
regulator-boot-on;
regulator-min-microvolt = <712500>;
regulator-max-microvolt = <1450000>;
regulator-ramp-delay = <12500>;
regulator-state-mem {
regulator-on-in-suspend;
regulator-suspend-microvolt = <950000>;
};
};
vcc_ddr: DCDC_REG3 {
regulator-name = "vcc_ddr";
regulator-always-on;
regulator-boot-on;
regulator-state-mem {
regulator-on-in-suspend;
};
};
vcc_io_33: DCDC_REG4 {
regulator-name = "vcc_io_33";
regulator-always-on;
regulator-boot-on;
regulator-min-microvolt = <3300000>;
regulator-max-microvolt = <3300000>;
regulator-state-mem {
regulator-on-in-suspend;
regulator-suspend-microvolt = <3300000>;
};
};
vcc_18: LDO_REG1 {
regulator-name = "vcc_18";
regulator-always-on;
regulator-boot-on;
regulator-min-microvolt = <1800000>;
regulator-max-microvolt = <1800000>;
regulator-state-mem {
regulator-on-in-suspend;
regulator-suspend-microvolt = <1800000>;
};
};
vcc18_emmc: LDO_REG2 {
regulator-name = "vcc18_emmc";
regulator-always-on;
regulator-boot-on;
regulator-min-microvolt = <1800000>;
regulator-max-microvolt = <1800000>;
regulator-state-mem {
regulator-on-in-suspend;
regulator-suspend-microvolt = <1800000>;
};
};
vdd_10: LDO_REG3 {
regulator-name = "vdd_10";
regulator-always-on;
regulator-boot-on;
regulator-min-microvolt = <1000000>;
regulator-max-microvolt = <1000000>;
regulator-state-mem {
regulator-on-in-suspend;
regulator-suspend-microvolt = <1000000>;
};
};
};
};
};
&io_domains {
pmuio-supply = <&vcc_io_33>;
vccio1-supply = <&vcc_io_33>;
vccio2-supply = <&vcc18_emmc>;
vccio3-supply = <&vcc_io_sdio>;
vccio4-supply = <&vcc_18>;
vccio5-supply = <&vcc_io_33>;
vccio6-supply = <&vcc_io_33>;
status = "okay";
};
&pinctrl {
button {
reset_button_pin: reset-button-pin {
rockchip,pins = <0 RK_PA0 RK_FUNC_GPIO &pcfg_pull_none>;
};
};
ethernet-phy {
eth_phy_reset_pin: eth-phy-reset-pin {
rockchip,pins = <1 RK_PC2 RK_FUNC_GPIO &pcfg_pull_down>;
};
};
leds {
lan_led_pin: lan-led-pin {
rockchip,pins = <2 RK_PB7 RK_FUNC_GPIO &pcfg_pull_none>;
};
sys_led_pin: sys-led-pin {
rockchip,pins = <0 RK_PA2 RK_FUNC_GPIO &pcfg_pull_none>;
};
wan_led_pin: wan-led-pin {
rockchip,pins = <2 RK_PC2 RK_FUNC_GPIO &pcfg_pull_none>;
};
};
pmic {
pmic_int_l: pmic-int-l {
rockchip,pins = <1 RK_PD0 RK_FUNC_GPIO &pcfg_pull_up>;
};
};
sd {
sdio_vcc_pin: sdio-vcc-pin {
rockchip,pins = <1 RK_PD4 RK_FUNC_GPIO &pcfg_pull_up>;
};
};
};
&pwm2 {
status = "okay";
};
&sdmmc {
bus-width = <4>;
cap-sd-highspeed;
disable-wp;
pinctrl-0 = <&sdmmc0_clk>, <&sdmmc0_cmd>, <&sdmmc0_dectn>, <&sdmmc0_bus4>;
pinctrl-names = "default";
sd-uhs-sdr12;
sd-uhs-sdr25;
sd-uhs-sdr50;
sd-uhs-sdr104;
vmmc-supply = <&vcc_sd>;
vqmmc-supply = <&vcc_io_sdio>;
status = "okay";
};
&tsadc {
rockchip,hw-tshut-mode = <0>;
rockchip,hw-tshut-polarity = <0>;
status = "okay";
};
&u2phy {
status = "okay";
};
&u2phy_host {
status = "okay";
};
&u2phy_otg {
status = "okay";
};
&uart2 {
status = "okay";
};
&usb20_otg {
status = "okay";
dr_mode = "host";
};
&usb_host0_ehci {
status = "okay";
};
&usb_host0_ohci {
status = "okay";
};

View file

@ -13,10 +13,6 @@
};
};
&rng {
status = "okay";
};
&i2c0 {
u-boot,dm-pre-reloc;
};
@ -38,6 +34,10 @@
status = "okay";
};
&vdd_center {
regulator-init-microvolt = <900000>;
};
&sdmmc {
u-boot,dm-pre-reloc;
bus-width = <4>;

View file

@ -11,3 +11,7 @@
u-boot,spl-boot-order = "same-as-spl", &sdhci, &sdmmc;
};
};
&vdd_log {
regulator-init-microvolt = <950000>;
};

View file

@ -11,3 +11,7 @@
u-boot,spl-boot-order = "same-as-spl", &sdhci, &sdmmc;
};
};
&vdd_log {
regulator-init-microvolt = <950000>;
};

View file

@ -24,10 +24,6 @@
u-boot,dm-pre-reloc;
};
&rng {
status = "okay";
};
&sdhci {
max-frequency = <25000000>;
u-boot,dm-pre-reloc;

View file

@ -28,8 +28,7 @@
};
aliases {
spi0 = &spi1;
spi1 = &spi5;
spi5 = &spi5;
};
/*

View file

@ -7,10 +7,6 @@
#include "rk3399-sdram-lpddr4-100.dtsi"
/ {
aliases {
spi0 = &spi1;
};
chosen {
u-boot,spl-boot-order = "same-as-spl", &spi_flash, &sdhci, &sdmmc;
};

View file

@ -15,10 +15,6 @@
};
};
&rng {
status = "okay";
};
&spi1 {
spi_flash: flash@0 {
u-boot,dm-pre-reloc;

View file

@ -32,7 +32,7 @@
rng: rng@ff8b8000 {
compatible = "rockchip,cryptov1-rng";
reg = <0x0 0xff8b8000 0x0 0x1000>;
status = "disabled";
status = "okay";
};
dmc: dmc {

View file

@ -5,6 +5,13 @@ F: board/rockchip/evb_rk3328
F: include/configs/evb_rk3328.h
F: configs/evb-rk3328_defconfig
NANOPI-R2S-RK3328
M: David Bauer <mail@david-bauer.net>
S: Maintained
F: configs/nanopi-r2s-rk3328_defconfig
F: arch/arm/dts/rk3328-nanopi-r2s-u-boot.dtsi
F: arch/arm/dts/rk3328-nanopi-r2s.dts
ROC-RK3328-CC
M: Loic Devulder <ldevulder@suse.com>
M: Chen-Yu Tsai <wens@csie.org>

View file

@ -35,6 +35,8 @@ CONFIG_MMC_DW=y
CONFIG_MMC_DW_ROCKCHIP=y
CONFIG_MMC_SDHCI=y
CONFIG_MMC_SDHCI_ROCKCHIP=y
CONFIG_DM_RNG=y
CONFIG_RNG_ROCKCHIP=y
CONFIG_SF_DEFAULT_SPEED=20000000
CONFIG_DM_ETH=y
CONFIG_ETH_DESIGNWARE=y

View file

@ -0,0 +1,98 @@
CONFIG_ARM=y
CONFIG_ARCH_ROCKCHIP=y
CONFIG_SYS_TEXT_BASE=0x00200000
CONFIG_SPL_GPIO_SUPPORT=y
CONFIG_ENV_OFFSET=0x3F8000
CONFIG_ROCKCHIP_RK3328=y
CONFIG_TPL_ROCKCHIP_COMMON_BOARD=y
CONFIG_TPL_LIBCOMMON_SUPPORT=y
CONFIG_TPL_LIBGENERIC_SUPPORT=y
CONFIG_SPL_DRIVERS_MISC_SUPPORT=y
CONFIG_SPL_STACK_R_ADDR=0x600000
CONFIG_NR_DRAM_BANKS=1
CONFIG_DEBUG_UART_BASE=0xFF130000
CONFIG_DEBUG_UART_CLOCK=24000000
CONFIG_SYSINFO=y
CONFIG_DEBUG_UART=y
CONFIG_TPL_SYS_MALLOC_F_LEN=0x800
# CONFIG_ANDROID_BOOT_IMAGE is not set
CONFIG_FIT=y
CONFIG_FIT_VERBOSE=y
CONFIG_SPL_LOAD_FIT=y
CONFIG_DEFAULT_FDT_FILE="rockchip/rk3328-nanopi-r2s.dtb"
CONFIG_MISC_INIT_R=y
# CONFIG_DISPLAY_CPUINFO is not set
CONFIG_DISPLAY_BOARDINFO_LATE=y
# CONFIG_SPL_RAW_IMAGE_SUPPORT is not set
CONFIG_TPL_SYS_MALLOC_SIMPLE=y
CONFIG_SPL_STACK_R=y
CONFIG_SPL_I2C_SUPPORT=y
CONFIG_SPL_POWER_SUPPORT=y
CONFIG_SPL_ATF=y
CONFIG_SPL_ATF_NO_PLATFORM_PARAM=y
CONFIG_CMD_BOOTZ=y
CONFIG_CMD_GPT=y
CONFIG_CMD_MMC=y
CONFIG_CMD_USB=y
# CONFIG_CMD_SETEXPR is not set
CONFIG_CMD_TIME=y
CONFIG_SPL_OF_CONTROL=y
CONFIG_TPL_OF_CONTROL=y
CONFIG_DEFAULT_DEVICE_TREE="rk3328-nanopi-r2s"
CONFIG_OF_SPL_REMOVE_PROPS="clock-names interrupt-parent assigned-clocks assigned-clock-rates assigned-clock-parents"
CONFIG_TPL_OF_PLATDATA=y
CONFIG_ENV_IS_IN_MMC=y
CONFIG_SYS_RELOC_GD_ENV_ADDR=y
CONFIG_NET_RANDOM_ETHADDR=y
CONFIG_TPL_DM=y
CONFIG_REGMAP=y
CONFIG_SPL_REGMAP=y
CONFIG_TPL_REGMAP=y
CONFIG_SYSCON=y
CONFIG_SPL_SYSCON=y
CONFIG_TPL_SYSCON=y
CONFIG_CLK=y
CONFIG_SPL_CLK=y
CONFIG_FASTBOOT_BUF_ADDR=0x800800
CONFIG_FASTBOOT_CMD_OEM_FORMAT=y
CONFIG_ROCKCHIP_GPIO=y
CONFIG_SYS_I2C_ROCKCHIP=y
CONFIG_MMC_DW=y
CONFIG_MMC_DW_ROCKCHIP=y
CONFIG_SF_DEFAULT_SPEED=20000000
CONFIG_DM_ETH=y
CONFIG_ETH_DESIGNWARE=y
CONFIG_GMAC_ROCKCHIP=y
CONFIG_PINCTRL=y
CONFIG_SPL_PINCTRL=y
CONFIG_DM_PMIC=y
CONFIG_PMIC_RK8XX=y
CONFIG_SPL_DM_REGULATOR=y
CONFIG_REGULATOR_PWM=y
CONFIG_DM_REGULATOR_FIXED=y
CONFIG_SPL_DM_REGULATOR_FIXED=y
CONFIG_REGULATOR_RK8XX=y
CONFIG_PWM_ROCKCHIP=y
CONFIG_RAM=y
CONFIG_SPL_RAM=y
CONFIG_TPL_RAM=y
CONFIG_DM_RESET=y
CONFIG_BAUDRATE=1500000
CONFIG_DEBUG_UART_SHIFT=2
CONFIG_SYSRESET=y
# CONFIG_TPL_SYSRESET is not set
CONFIG_USB=y
CONFIG_USB_XHCI_HCD=y
CONFIG_USB_XHCI_DWC3=y
CONFIG_USB_EHCI_HCD=y
CONFIG_USB_EHCI_GENERIC=y
CONFIG_USB_OHCI_HCD=y
CONFIG_USB_OHCI_GENERIC=y
CONFIG_USB_DWC2=y
CONFIG_USB_DWC3=y
# CONFIG_USB_DWC3_GADGET is not set
CONFIG_USB_GADGET=y
CONFIG_USB_GADGET_DWC2_OTG=y
CONFIG_SPL_TINY_MEMSET=y
CONFIG_TPL_TINY_MEMSET=y
CONFIG_ERRNO_STR=y

View file

@ -44,6 +44,7 @@ CONFIG_ENV_OVERWRITE=y
CONFIG_ENV_IS_IN_MMC=y
CONFIG_SYS_RELOC_GD_ENV_ADDR=y
CONFIG_SYS_MMC_ENV_DEV=1
CONFIG_SPL_DM_SEQ_ALIAS=y
CONFIG_ROCKCHIP_GPIO=y
CONFIG_SYS_I2C_ROCKCHIP=y
CONFIG_MISC=y
@ -53,6 +54,7 @@ CONFIG_MMC_DW_ROCKCHIP=y
CONFIG_MMC_SDHCI=y
CONFIG_MMC_SDHCI_SDMA=y
CONFIG_MMC_SDHCI_ROCKCHIP=y
CONFIG_SF_DEFAULT_BUS=1
CONFIG_SF_DEFAULT_SPEED=20000000
CONFIG_SPI_FLASH_GIGADEVICE=y
CONFIG_SPI_FLASH_WINBOND=y

View file

@ -42,6 +42,7 @@ CONFIG_MMC_DW=y
CONFIG_MMC_DW_ROCKCHIP=y
CONFIG_MMC_SDHCI=y
CONFIG_MMC_SDHCI_ROCKCHIP=y
CONFIG_SF_DEFAULT_BUS=1
CONFIG_SPI_FLASH_WINBOND=y
CONFIG_DM_ETH=y
CONFIG_ETH_DESIGNWARE=y

View file

@ -41,6 +41,7 @@ CONFIG_MMC_DW=y
CONFIG_MMC_DW_ROCKCHIP=y
CONFIG_MMC_SDHCI=y
CONFIG_MMC_SDHCI_ROCKCHIP=y
CONFIG_SF_DEFAULT_BUS=1
CONFIG_SPI_FLASH_WINBOND=y
CONFIG_DM_ETH=y
CONFIG_ETH_DESIGNWARE=y

View file

@ -39,6 +39,8 @@ CONFIG_MMC_DW_ROCKCHIP=y
CONFIG_MMC_SDHCI=y
CONFIG_MMC_SDHCI_SDMA=y
CONFIG_MMC_SDHCI_ROCKCHIP=y
CONFIG_DM_RNG=y
CONFIG_RNG_ROCKCHIP=y
CONFIG_DM_ETH=y
CONFIG_NVME=y
CONFIG_PCI=y

View file

@ -42,6 +42,8 @@ CONFIG_MMC_DW=y
CONFIG_MMC_DW_ROCKCHIP=y
CONFIG_MMC_SDHCI=y
CONFIG_MMC_SDHCI_ROCKCHIP=y
CONFIG_DM_RNG=y
CONFIG_RNG_ROCKCHIP=y
CONFIG_SF_DEFAULT_BUS=1
CONFIG_SPI_FLASH_GIGADEVICE=y
CONFIG_DM_ETH=y

View file

@ -281,6 +281,15 @@ config PCIE_ROCKCHIP
Say Y here if you want to enable PCIe controller support on
Rockchip SoCs.
config PCIE_DW_ROCKCHIP
bool "Rockchip DesignWare based PCIe controller"
depends on ARCH_ROCKCHIP
select DM_PCI
select PHY_ROCKCHIP_SNPS_PCIE3
help
Say Y here if you want to enable DW PCIe controller support on
Rockchip SoCs.
config PCI_BRCMSTB
bool "Broadcom STB PCIe controller"
depends on DM_PCI

View file

@ -48,5 +48,6 @@ obj-$(CONFIG_PCIE_INTEL_FPGA) += pcie_intel_fpga.o
obj-$(CONFIG_PCI_KEYSTONE) += pcie_dw_ti.o
obj-$(CONFIG_PCIE_MEDIATEK) += pcie_mediatek.o
obj-$(CONFIG_PCIE_ROCKCHIP) += pcie_rockchip.o
obj-$(CONFIG_PCIE_DW_ROCKCHIP) += pcie_dw_rockchip.o
obj-$(CONFIG_PCI_BRCMSTB) += pcie_brcmstb.o
obj-$(CONFIG_PCI_OCTEONTX) += pci_octeontx.o

View file

@ -0,0 +1,877 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* Rockchip DesignWare based PCIe host controller driver
*
* Copyright (c) 2021 Rockchip, Inc.
*/
#include <common.h>
#include <clk.h>
#include <dm.h>
#include <generic-phy.h>
#include <pci.h>
#include <power-domain.h>
#include <reset.h>
#include <syscon.h>
#include <asm/arch-rockchip/clock.h>
#include <asm/io.h>
#include <asm-generic/gpio.h>
#include <dm/device_compat.h>
#include <linux/iopoll.h>
#include <linux/delay.h>
#include <power/regulator.h>
DECLARE_GLOBAL_DATA_PTR;
/**
* struct rk_pcie - RK DW PCIe controller state
*
* @vpcie3v3: The 3.3v power supply for slot
* @dbi_base: The base address of dwc core regs
* @apb_base: The base address of vendor regs
* @cfg_base: The base address of config header space
* @cfg_size: The size of the configuration space which is needed
* as it gets written into the PCIE_ATU_LIMIT register
* @first_busno: This driver supports multiple PCIe controllers.
* first_busno stores the bus number of the PCIe root-port
* number which may vary depending on the PCIe setup
* (PEX switches etc).
* @rst_gpio: The #PERST signal for slot
* @io: The IO space for EP's BAR
* @mem: The memory space for EP's BAR
*/
struct rk_pcie {
struct udevice *dev;
struct udevice *vpcie3v3;
void *dbi_base;
void *apb_base;
void *cfg_base;
fdt_size_t cfg_size;
struct phy phy;
struct clk_bulk clks;
int first_busno;
struct reset_ctl_bulk rsts;
struct gpio_desc rst_gpio;
struct pci_region io;
struct pci_region mem;
};
/* Parameters for the waiting for iATU enabled routine */
#define PCIE_CLIENT_GENERAL_DEBUG 0x104
#define PCIE_CLIENT_HOT_RESET_CTRL 0x180
#define PCIE_LTSSM_ENABLE_ENHANCE BIT(4)
#define PCIE_CLIENT_LTSSM_STATUS 0x300
#define SMLH_LINKUP BIT(16)
#define RDLH_LINKUP BIT(17)
#define PCIE_CLIENT_DBG_FIFO_MODE_CON 0x310
#define PCIE_CLIENT_DBG_FIFO_PTN_HIT_D0 0x320
#define PCIE_CLIENT_DBG_FIFO_PTN_HIT_D1 0x324
#define PCIE_CLIENT_DBG_FIFO_TRN_HIT_D0 0x328
#define PCIE_CLIENT_DBG_FIFO_TRN_HIT_D1 0x32c
#define PCIE_CLIENT_DBG_FIFO_STATUS 0x350
#define PCIE_CLIENT_DBG_TRANSITION_DATA 0xffff0000
#define PCIE_CLIENT_DBF_EN 0xffff0003
/* PCI DBICS registers */
#define PCIE_LINK_STATUS_REG 0x80
#define PCIE_LINK_STATUS_SPEED_OFF 16
#define PCIE_LINK_STATUS_SPEED_MASK (0xf << PCIE_LINK_STATUS_SPEED_OFF)
#define PCIE_LINK_STATUS_WIDTH_OFF 20
#define PCIE_LINK_STATUS_WIDTH_MASK (0xf << PCIE_LINK_STATUS_WIDTH_OFF)
#define PCIE_LINK_CAPABILITY 0x7c
#define PCIE_LINK_CTL_2 0xa0
#define TARGET_LINK_SPEED_MASK 0xf
#define LINK_SPEED_GEN_1 0x1
#define LINK_SPEED_GEN_2 0x2
#define LINK_SPEED_GEN_3 0x3
#define PCIE_MISC_CONTROL_1_OFF 0x8bc
#define PCIE_DBI_RO_WR_EN BIT(0)
#define PCIE_LINK_WIDTH_SPEED_CONTROL 0x80c
#define PORT_LOGIC_SPEED_CHANGE BIT(17)
/*
* iATU Unroll-specific register definitions
* From 4.80 core version the address translation will be made by unroll.
* The registers are offset from atu_base
*/
#define PCIE_ATU_UNR_REGION_CTRL1 0x00
#define PCIE_ATU_UNR_REGION_CTRL2 0x04
#define PCIE_ATU_UNR_LOWER_BASE 0x08
#define PCIE_ATU_UNR_UPPER_BASE 0x0c
#define PCIE_ATU_UNR_LIMIT 0x10
#define PCIE_ATU_UNR_LOWER_TARGET 0x14
#define PCIE_ATU_UNR_UPPER_TARGET 0x18
#define PCIE_ATU_REGION_INDEX1 (0x1 << 0)
#define PCIE_ATU_REGION_INDEX0 (0x0 << 0)
#define PCIE_ATU_TYPE_MEM (0x0 << 0)
#define PCIE_ATU_TYPE_IO (0x2 << 0)
#define PCIE_ATU_TYPE_CFG0 (0x4 << 0)
#define PCIE_ATU_TYPE_CFG1 (0x5 << 0)
#define PCIE_ATU_ENABLE (0x1 << 31)
#define PCIE_ATU_BAR_MODE_ENABLE (0x1 << 30)
#define PCIE_ATU_BUS(x) (((x) & 0xff) << 24)
#define PCIE_ATU_DEV(x) (((x) & 0x1f) << 19)
#define PCIE_ATU_FUNC(x) (((x) & 0x7) << 16)
/* Register address builder */
#define PCIE_GET_ATU_OUTB_UNR_REG_OFFSET(region) \
((0x3 << 20) | ((region) << 9))
/* Parameters for the waiting for iATU enabled routine */
#define LINK_WAIT_MAX_IATU_RETRIES 5
#define LINK_WAIT_IATU_US 10000
/* Parameters for the waiting for #perst signal */
#define PERST_WAIT_MS 1000
static int rk_pcie_read(void __iomem *addr, int size, u32 *val)
{
if ((uintptr_t)addr & (size - 1)) {
*val = 0;
return PCIBIOS_UNSUPPORTED;
}
if (size == 4) {
*val = readl(addr);
} else if (size == 2) {
*val = readw(addr);
} else if (size == 1) {
*val = readb(addr);
} else {
*val = 0;
return -ENODEV;
}
return 0;
}
static int rk_pcie_write(void __iomem *addr, int size, u32 val)
{
if ((uintptr_t)addr & (size - 1))
return PCIBIOS_UNSUPPORTED;
if (size == 4)
writel(val, addr);
else if (size == 2)
writew(val, addr);
else if (size == 1)
writeb(val, addr);
else
return -ENODEV;
return 0;
}
static u32 __rk_pcie_read_apb(struct rk_pcie *rk_pcie, void __iomem *base,
u32 reg, size_t size)
{
int ret;
u32 val;
ret = rk_pcie_read(base + reg, size, &val);
if (ret)
dev_err(rk_pcie->dev, "Read APB address failed\n");
return val;
}
static void __rk_pcie_write_apb(struct rk_pcie *rk_pcie, void __iomem *base,
u32 reg, size_t size, u32 val)
{
int ret;
ret = rk_pcie_write(base + reg, size, val);
if (ret)
dev_err(rk_pcie->dev, "Write APB address failed\n");
}
/**
* rk_pcie_readl_apb() - Read vendor regs
*
* @rk_pcie: Pointer to the PCI controller state
* @reg: Offset of regs
*/
static inline u32 rk_pcie_readl_apb(struct rk_pcie *rk_pcie, u32 reg)
{
return __rk_pcie_read_apb(rk_pcie, rk_pcie->apb_base, reg, 0x4);
}
/**
* rk_pcie_writel_apb() - Write vendor regs
*
* @rk_pcie: Pointer to the PCI controller state
* @reg: Offset of regs
* @val: Value to be writen
*/
static inline void rk_pcie_writel_apb(struct rk_pcie *rk_pcie, u32 reg,
u32 val)
{
__rk_pcie_write_apb(rk_pcie, rk_pcie->apb_base, reg, 0x4, val);
}
static int rk_pcie_get_link_speed(struct rk_pcie *rk_pcie)
{
return (readl(rk_pcie->dbi_base + PCIE_LINK_STATUS_REG) &
PCIE_LINK_STATUS_SPEED_MASK) >> PCIE_LINK_STATUS_SPEED_OFF;
}
static int rk_pcie_get_link_width(struct rk_pcie *rk_pcie)
{
return (readl(rk_pcie->dbi_base + PCIE_LINK_STATUS_REG) &
PCIE_LINK_STATUS_WIDTH_MASK) >> PCIE_LINK_STATUS_WIDTH_OFF;
}
static void rk_pcie_writel_ob_unroll(struct rk_pcie *rk_pcie, u32 index,
u32 reg, u32 val)
{
u32 offset = PCIE_GET_ATU_OUTB_UNR_REG_OFFSET(index);
void __iomem *base = rk_pcie->dbi_base;
writel(val, base + offset + reg);
}
static u32 rk_pcie_readl_ob_unroll(struct rk_pcie *rk_pcie, u32 index, u32 reg)
{
u32 offset = PCIE_GET_ATU_OUTB_UNR_REG_OFFSET(index);
void __iomem *base = rk_pcie->dbi_base;
return readl(base + offset + reg);
}
static inline void rk_pcie_dbi_write_enable(struct rk_pcie *rk_pcie, bool en)
{
u32 val;
val = readl(rk_pcie->dbi_base + PCIE_MISC_CONTROL_1_OFF);
if (en)
val |= PCIE_DBI_RO_WR_EN;
else
val &= ~PCIE_DBI_RO_WR_EN;
writel(val, rk_pcie->dbi_base + PCIE_MISC_CONTROL_1_OFF);
}
/**
* rockchip_pcie_setup_host() - Setup the PCIe controller for RC opertaion
*
* @rk_pcie: Pointer to the PCI controller state
*
* Configure the host BARs of the PCIe controller root port so that
* PCI(e) devices may access the system memory.
*/
static void rk_pcie_setup_host(struct rk_pcie *rk_pcie)
{
u32 val;
rk_pcie_dbi_write_enable(rk_pcie, true);
/* setup RC BARs */
writel(PCI_BASE_ADDRESS_MEM_TYPE_64,
rk_pcie->dbi_base + PCI_BASE_ADDRESS_0);
writel(0x0, rk_pcie->dbi_base + PCI_BASE_ADDRESS_1);
/* setup interrupt pins */
clrsetbits_le32(rk_pcie->dbi_base + PCI_INTERRUPT_LINE,
0xff00, 0x100);
/* setup bus numbers */
clrsetbits_le32(rk_pcie->dbi_base + PCI_PRIMARY_BUS,
0xffffff, 0x00ff0100);
/* setup command register */
clrsetbits_le32(rk_pcie->dbi_base + PCI_PRIMARY_BUS,
0xffff,
PCI_COMMAND_IO | PCI_COMMAND_MEMORY |
PCI_COMMAND_MASTER | PCI_COMMAND_SERR);
/* program correct class for RC */
writew(PCI_CLASS_BRIDGE_PCI, rk_pcie->dbi_base + PCI_CLASS_DEVICE);
/* Better disable write permission right after the update */
setbits_le32(rk_pcie->dbi_base + PCIE_LINK_WIDTH_SPEED_CONTROL,
PORT_LOGIC_SPEED_CHANGE)
rk_pcie_dbi_write_enable(rk_pcie, false);
}
/**
* rk_pcie_configure() - Configure link capabilities and speed
*
* @rk_pcie: Pointer to the PCI controller state
* @cap_speed: The capabilities and speed to configure
*
* Configure the link capabilities and speed in the PCIe root complex.
*/
static void rk_pcie_configure(struct rk_pcie *pci, u32 cap_speed)
{
u32 val;
rk_pcie_dbi_write_enable(pci, true);
clrsetbits_le32(pci->dbi_base + PCIE_LINK_CAPABILITY,
TARGET_LINK_SPEED_MASK, cap_speed);
clrsetbits_le32(pci->dbi_base + PCIE_LINK_CTL_2,
TARGET_LINK_SPEED_MASK, cap_speed);
rk_pcie_dbi_write_enable(pci, false);
}
/**
* rk_pcie_dw_prog_outbound_atu_unroll() - Configure ATU for outbound accesses
*
* @rk_pcie: Pointer to the PCI controller state
* @index: ATU region index
* @type: ATU accsess type
* @cpu_addr: the physical address for the translation entry
* @pci_addr: the pcie bus address for the translation entry
* @size: the size of the translation entry
*
* Return: 0 is successful and -1 is failure
*/
static int rk_pcie_prog_outbound_atu_unroll(struct rk_pcie *pci, int index,
int type, u64 cpu_addr,
u64 pci_addr, u32 size)
{
u32 retries, val;
dev_dbg(pci->dev, "ATU programmed with: index: %d, type: %d, cpu addr: %8llx, pci addr: %8llx, size: %8x\n",
index, type, cpu_addr, pci_addr, size);
rk_pcie_writel_ob_unroll(pci, index, PCIE_ATU_UNR_LOWER_BASE,
lower_32_bits(cpu_addr));
rk_pcie_writel_ob_unroll(pci, index, PCIE_ATU_UNR_UPPER_BASE,
upper_32_bits(cpu_addr));
rk_pcie_writel_ob_unroll(pci, index, PCIE_ATU_UNR_LIMIT,
lower_32_bits(cpu_addr + size - 1));
rk_pcie_writel_ob_unroll(pci, index, PCIE_ATU_UNR_LOWER_TARGET,
lower_32_bits(pci_addr));
rk_pcie_writel_ob_unroll(pci, index, PCIE_ATU_UNR_UPPER_TARGET,
upper_32_bits(pci_addr));
rk_pcie_writel_ob_unroll(pci, index, PCIE_ATU_UNR_REGION_CTRL1,
type);
rk_pcie_writel_ob_unroll(pci, index, PCIE_ATU_UNR_REGION_CTRL2,
PCIE_ATU_ENABLE);
/*
* Make sure ATU enable takes effect before any subsequent config
* and I/O accesses.
*/
for (retries = 0; retries < LINK_WAIT_MAX_IATU_RETRIES; retries++) {
val = rk_pcie_readl_ob_unroll(pci, index,
PCIE_ATU_UNR_REGION_CTRL2);
if (val & PCIE_ATU_ENABLE)
return 0;
udelay(LINK_WAIT_IATU_US);
}
dev_err(pci->dev, "outbound iATU is not being enabled\n");
return -1;
}
/**
* rk_pcie_dw_addr_valid() - Check for valid bus address
*
* @d: The PCI device to access
* @first_busno: Bus number of the PCIe controller root complex
*
* Return 1 (true) if the PCI device can be accessed by this controller.
*
* Return: 1 on valid, 0 on invalid
*/
static int rk_pcie_addr_valid(pci_dev_t d, int first_busno)
{
if ((PCI_BUS(d) == first_busno) && (PCI_DEV(d) > 0))
return 0;
if ((PCI_BUS(d) == first_busno + 1) && (PCI_DEV(d) > 0))
return 0;
return 1;
}
/**
* set_cfg_address() - Configure the PCIe controller config space access
*
* @rk_pcie: Pointer to the PCI controller state
* @d: PCI device to access
* @where: Offset in the configuration space
*
* Configures the PCIe controller to access the configuration space of
* a specific PCIe device and returns the address to use for this
* access.
*
* Return: Address that can be used to access the configation space
* of the requested device / offset
*/
static uintptr_t set_cfg_address(struct rk_pcie *pcie,
pci_dev_t d, uint where)
{
int rel_bus = PCI_BUS(d) - pcie->first_busno;
uintptr_t va_address;
u32 atu_type;
int ret;
/* Use dbi_base for own configuration read and write */
if (!rel_bus) {
va_address = (uintptr_t)pcie->dbi_base;
goto out;
}
if (rel_bus == 1)
/*
* For local bus whose primary bus number is root bridge,
* change TLP Type field to 4.
*/
atu_type = PCIE_ATU_TYPE_CFG0;
else
/* Otherwise, change TLP Type field to 5. */
atu_type = PCIE_ATU_TYPE_CFG1;
/*
* Not accessing root port configuration space?
* Region #0 is used for Outbound CFG space access.
* Direction = Outbound
* Region Index = 0
*/
d = PCI_MASK_BUS(d);
d = PCI_ADD_BUS(rel_bus, d);
ret = rk_pcie_prog_outbound_atu_unroll(pcie, PCIE_ATU_REGION_INDEX1,
atu_type, (u64)pcie->cfg_base,
d << 8, pcie->cfg_size);
if (ret)
return (uintptr_t)ret;
va_address = (uintptr_t)pcie->cfg_base;
out:
va_address += where & ~0x3;
return va_address;
}
/**
* rockchip_pcie_rd_conf() - Read from configuration space
*
* @bus: Pointer to the PCI bus
* @bdf: Identifies the PCIe device to access
* @offset: The offset into the device's configuration space
* @valuep: A pointer at which to store the read value
* @size: Indicates the size of access to perform
*
* Read a value of size @size from offset @offset within the configuration
* space of the device identified by the bus, device & function numbers in @bdf
* on the PCI bus @bus.
*
* Return: 0 on success
*/
static int rockchip_pcie_rd_conf(const struct udevice *bus, pci_dev_t bdf,
uint offset, ulong *valuep,
enum pci_size_t size)
{
struct rk_pcie *pcie = dev_get_priv(bus);
uintptr_t va_address;
ulong value;
debug("PCIE CFG read: bdf=%2x:%2x:%2x\n",
PCI_BUS(bdf), PCI_DEV(bdf), PCI_FUNC(bdf));
if (!rk_pcie_addr_valid(bdf, pcie->first_busno)) {
debug("- out of range\n");
*valuep = pci_get_ff(size);
return 0;
}
va_address = set_cfg_address(pcie, bdf, offset);
value = readl(va_address);
debug("(addr,val)=(0x%04x, 0x%08lx)\n", offset, value);
*valuep = pci_conv_32_to_size(value, offset, size);
return rk_pcie_prog_outbound_atu_unroll(pcie,
PCIE_ATU_REGION_INDEX1,
PCIE_ATU_TYPE_IO,
pcie->io.phys_start,
pcie->io.bus_start,
pcie->io.size);
}
/**
* rockchip_pcie_wr_conf() - Write to configuration space
*
* @bus: Pointer to the PCI bus
* @bdf: Identifies the PCIe device to access
* @offset: The offset into the device's configuration space
* @value: The value to write
* @size: Indicates the size of access to perform
*
* Write the value @value of size @size from offset @offset within the
* configuration space of the device identified by the bus, device & function
* numbers in @bdf on the PCI bus @bus.
*
* Return: 0 on success
*/
static int rockchip_pcie_wr_conf(struct udevice *bus, pci_dev_t bdf,
uint offset, ulong value,
enum pci_size_t size)
{
struct rk_pcie *pcie = dev_get_priv(bus);
uintptr_t va_address;
ulong old;
debug("PCIE CFG write: (b,d,f)=(%2d,%2d,%2d)\n",
PCI_BUS(bdf), PCI_DEV(bdf), PCI_FUNC(bdf));
debug("(addr,val)=(0x%04x, 0x%08lx)\n", offset, value);
if (!rk_pcie_addr_valid(bdf, pcie->first_busno)) {
debug("- out of range\n");
return 0;
}
va_address = set_cfg_address(pcie, bdf, offset);
old = readl(va_address);
value = pci_conv_size_to_32(old, value, offset, size);
writel(value, va_address);
return rk_pcie_prog_outbound_atu_unroll(pcie,
PCIE_ATU_REGION_INDEX1,
PCIE_ATU_TYPE_IO,
pcie->io.phys_start,
pcie->io.bus_start,
pcie->io.size);
}
static void rk_pcie_enable_debug(struct rk_pcie *rk_pcie)
{
rk_pcie_writel_apb(rk_pcie, PCIE_CLIENT_DBG_FIFO_PTN_HIT_D0,
PCIE_CLIENT_DBG_TRANSITION_DATA);
rk_pcie_writel_apb(rk_pcie, PCIE_CLIENT_DBG_FIFO_PTN_HIT_D1,
PCIE_CLIENT_DBG_TRANSITION_DATA);
rk_pcie_writel_apb(rk_pcie, PCIE_CLIENT_DBG_FIFO_TRN_HIT_D0,
PCIE_CLIENT_DBG_TRANSITION_DATA);
rk_pcie_writel_apb(rk_pcie, PCIE_CLIENT_DBG_FIFO_TRN_HIT_D1,
PCIE_CLIENT_DBG_TRANSITION_DATA);
rk_pcie_writel_apb(rk_pcie, PCIE_CLIENT_DBG_FIFO_MODE_CON,
PCIE_CLIENT_DBF_EN);
}
static void rk_pcie_debug_dump(struct rk_pcie *rk_pcie)
{
u32 loop;
debug("ltssm = 0x%x\n",
rk_pcie_readl_apb(rk_pcie, PCIE_CLIENT_LTSSM_STATUS));
for (loop = 0; loop < 64; loop++)
debug("fifo_status = 0x%x\n",
rk_pcie_readl_apb(rk_pcie, PCIE_CLIENT_DBG_FIFO_STATUS));
}
static inline void rk_pcie_link_status_clear(struct rk_pcie *rk_pcie)
{
rk_pcie_writel_apb(rk_pcie, PCIE_CLIENT_GENERAL_DEBUG, 0x0);
}
static inline void rk_pcie_disable_ltssm(struct rk_pcie *rk_pcie)
{
rk_pcie_writel_apb(rk_pcie, 0x0, 0xc0008);
}
static inline void rk_pcie_enable_ltssm(struct rk_pcie *rk_pcie)
{
rk_pcie_writel_apb(rk_pcie, 0x0, 0xc000c);
}
static int is_link_up(struct rk_pcie *priv)
{
u32 val;
val = rk_pcie_readl_apb(priv, PCIE_CLIENT_LTSSM_STATUS);
if ((val & (RDLH_LINKUP | SMLH_LINKUP)) == 0x30000 &&
(val & GENMASK(5, 0)) == 0x11)
return 1;
return 0;
}
/**
* rk_pcie_link_up() - Wait for the link to come up
*
* @rk_pcie: Pointer to the PCI controller state
* @cap_speed: Desired link speed
*
* Return: 1 (true) for active line and negetive (false) for no link (timeout)
*/
static int rk_pcie_link_up(struct rk_pcie *priv, u32 cap_speed)
{
int retries;
if (is_link_up(priv)) {
printf("PCI Link already up before configuration!\n");
return 1;
}
/* DW pre link configurations */
rk_pcie_configure(priv, cap_speed);
/* Rest the device */
if (dm_gpio_is_valid(&priv->rst_gpio)) {
dm_gpio_set_value(&priv->rst_gpio, 0);
/*
* Minimal is 100ms from spec but we see
* some wired devices need much more, such as 600ms.
* Add a enough delay to cover all cases.
*/
msleep(PERST_WAIT_MS);
dm_gpio_set_value(&priv->rst_gpio, 1);
}
rk_pcie_disable_ltssm(priv);
rk_pcie_link_status_clear(priv);
rk_pcie_enable_debug(priv);
/* Enable LTSSM */
rk_pcie_enable_ltssm(priv);
for (retries = 0; retries < 5; retries++) {
if (is_link_up(priv)) {
dev_info(priv->dev, "PCIe Link up, LTSSM is 0x%x\n",
rk_pcie_readl_apb(priv, PCIE_CLIENT_LTSSM_STATUS));
rk_pcie_debug_dump(priv);
return 0;
}
dev_info(priv->dev, "PCIe Linking... LTSSM is 0x%x\n",
rk_pcie_readl_apb(priv, PCIE_CLIENT_LTSSM_STATUS));
rk_pcie_debug_dump(priv);
msleep(1000);
}
dev_err(priv->dev, "PCIe-%d Link Fail\n", dev_seq(priv->dev));
/* Link maybe in Gen switch recovery but we need to wait more 1s */
msleep(1000);
return -EIO;
}
static int rockchip_pcie_init_port(struct udevice *dev)
{
int ret;
u32 val;
struct rk_pcie *priv = dev_get_priv(dev);
/* Set power and maybe external ref clk input */
if (priv->vpcie3v3) {
ret = regulator_set_value(priv->vpcie3v3, 3300000);
if (ret) {
dev_err(priv->dev, "failed to enable vpcie3v3 (ret=%d)\n",
ret);
return ret;
}
}
msleep(1000);
ret = generic_phy_init(&priv->phy);
if (ret) {
dev_err(dev, "failed to init phy (ret=%d)\n", ret);
return ret;
}
ret = generic_phy_power_on(&priv->phy);
if (ret) {
dev_err(dev, "failed to power on phy (ret=%d)\n", ret);
goto err_exit_phy;
}
ret = reset_deassert_bulk(&priv->rsts);
if (ret) {
dev_err(dev, "failed to deassert resets (ret=%d)\n", ret);
goto err_power_off_phy;
}
ret = clk_enable_bulk(&priv->clks);
if (ret) {
dev_err(dev, "failed to enable clks (ret=%d)\n", ret);
goto err_deassert_bulk;
}
/* LTSSM EN ctrl mode */
val = rk_pcie_readl_apb(priv, PCIE_CLIENT_HOT_RESET_CTRL);
val |= PCIE_LTSSM_ENABLE_ENHANCE | (PCIE_LTSSM_ENABLE_ENHANCE << 16);
rk_pcie_writel_apb(priv, PCIE_CLIENT_HOT_RESET_CTRL, val);
/* Set RC mode */
rk_pcie_writel_apb(priv, 0x0, 0xf00040);
rk_pcie_setup_host(priv);
ret = rk_pcie_link_up(priv, LINK_SPEED_GEN_3);
if (ret < 0)
goto err_link_up;
return 0;
err_link_up:
clk_disable_bulk(&priv->clks);
err_deassert_bulk:
reset_assert_bulk(&priv->rsts);
err_power_off_phy:
generic_phy_power_off(&priv->phy);
err_exit_phy:
generic_phy_exit(&priv->phy);
return ret;
}
static int rockchip_pcie_parse_dt(struct udevice *dev)
{
struct rk_pcie *priv = dev_get_priv(dev);
int ret;
priv->dbi_base = (void *)dev_read_addr_index(dev, 0);
if (!priv->dbi_base)
return -ENODEV;
dev_dbg(dev, "DBI address is 0x%p\n", priv->dbi_base);
priv->apb_base = (void *)dev_read_addr_index(dev, 1);
if (!priv->apb_base)
return -ENODEV;
dev_dbg(dev, "APB address is 0x%p\n", priv->apb_base);
ret = gpio_request_by_name(dev, "reset-gpios", 0,
&priv->rst_gpio, GPIOD_IS_OUT);
if (ret) {
dev_err(dev, "failed to find reset-gpios property\n");
return ret;
}
ret = reset_get_bulk(dev, &priv->rsts);
if (ret) {
dev_err(dev, "Can't get reset: %d\n", ret);
return ret;
}
ret = clk_get_bulk(dev, &priv->clks);
if (ret) {
dev_err(dev, "Can't get clock: %d\n", ret);
return ret;
}
ret = device_get_supply_regulator(dev, "vpcie3v3-supply",
&priv->vpcie3v3);
if (ret && ret != -ENOENT) {
dev_err(dev, "failed to get vpcie3v3 supply (ret=%d)\n", ret);
return ret;
}
ret = generic_phy_get_by_index(dev, 0, &priv->phy);
if (ret) {
dev_err(dev, "failed to get pcie phy (ret=%d)\n", ret);
return ret;
}
return 0;
}
/**
* rockchip_pcie_probe() - Probe the PCIe bus for active link
*
* @dev: A pointer to the device being operated on
*
* Probe for an active link on the PCIe bus and configure the controller
* to enable this port.
*
* Return: 0 on success, else -ENODEV
*/
static int rockchip_pcie_probe(struct udevice *dev)
{
struct rk_pcie *priv = dev_get_priv(dev);
struct udevice *ctlr = pci_get_controller(dev);
struct pci_controller *hose = dev_get_uclass_priv(ctlr);
int reti = 0;
priv->first_busno = dev_seq(dev);
priv->dev = dev;
ret = rockchip_pcie_parse_dt(dev);
if (ret)
return ret;
ret = rockchip_pcie_init_port(dev);
if (ret)
return ret;
dev_info(dev, "PCIE-%d: Link up (Gen%d-x%d, Bus%d)\n",
dev_seq(dev), rk_pcie_get_link_speed(priv),
rk_pcie_get_link_width(priv),
hose->first_busno);
for (ret = 0; ret < hose->region_count; ret++) {
if (hose->regions[ret].flags == PCI_REGION_IO) {
priv->io.phys_start = hose->regions[ret].phys_start; /* IO base */
priv->io.bus_start = hose->regions[ret].bus_start; /* IO_bus_addr */
priv->io.size = hose->regions[ret].size; /* IO size */
} else if (hose->regions[ret].flags == PCI_REGION_MEM) {
priv->mem.phys_start = hose->regions[ret].phys_start; /* MEM base */
priv->mem.bus_start = hose->regions[ret].bus_start; /* MEM_bus_addr */
priv->mem.size = hose->regions[ret].size; /* MEM size */
} else if (hose->regions[ret].flags == PCI_REGION_SYS_MEMORY) {
priv->cfg_base = (void *)(priv->io.phys_start - priv->io.size);
priv->cfg_size = priv->io.size;
} else {
dev_err(dev, "invalid flags type!\n");
}
}
dev_dbg(dev, "Config space: [0x%p - 0x%p, size 0x%llx]\n",
priv->cfg_base, priv->cfg_base + priv->cfg_size,
priv->cfg_size);
dev_dbg(dev, "IO space: [0x%llx - 0x%llx, size 0x%lx]\n",
priv->io.phys_start, priv->io.phys_start + priv->io.size,
priv->io.size);
dev_dbg(dev, "IO bus: [0x%lx - 0x%lx, size 0x%lx]\n",
priv->io.bus_start, priv->io.bus_start + priv->io.size,
priv->io.size);
dev_dbg(dev, "MEM space: [0x%llx - 0x%llx, size 0x%lx]\n",
priv->mem.phys_start, priv->mem.phys_start + priv->mem.size,
priv->mem.size);
dev_dbg(dev, "MEM bus: [0x%lx - 0x%lx, size 0x%lx]\n",
priv->mem.bus_start, priv->mem.bus_start + priv->mem.size,
priv->mem.size);
return rk_pcie_prog_outbound_atu_unroll(priv,
PCIE_ATU_REGION_INDEX0,
PCIE_ATU_TYPE_MEM,
priv->mem.phys_start,
priv->mem.bus_start,
priv->mem.size);
}
static const struct dm_pci_ops rockchip_pcie_ops = {
.read_config = rockchip_pcie_rd_conf,
.write_config = rockchip_pcie_wr_conf,
};
static const struct udevice_id rockchip_pcie_ids[] = {
{ .compatible = "rockchip,rk3568-pcie" },
{ }
};
U_BOOT_DRIVER(rockchip_dw_pcie) = {
.name = "pcie_dw_rockchip",
.id = UCLASS_PCI,
.of_match = rockchip_pcie_ids,
.ops = &rockchip_pcie_ops,
.probe = rockchip_pcie_probe,
.priv_auto = sizeof(struct rk_pcie),
};

View file

@ -18,6 +18,15 @@ config PHY_ROCKCHIP_PCIE
help
Enable this to support the Rockchip PCIe PHY.
config PHY_ROCKCHIP_SNPS_PCIE3
bool "Rockchip Snps PCIe3 PHY Driver"
depends on PHY && ARCH_ROCKCHIP
help
Support for Rockchip PCIe3 PHY with Synopsys IP block.
It could support PCIe Gen3 single root complex, and could
also be able splited into multiple combinations of lanes.
config PHY_ROCKCHIP_TYPEC
bool "Rockchip TYPEC PHY Driver"
depends on ARCH_ROCKCHIP

View file

@ -5,4 +5,5 @@
obj-$(CONFIG_PHY_ROCKCHIP_INNO_USB2) += phy-rockchip-inno-usb2.o
obj-$(CONFIG_PHY_ROCKCHIP_PCIE) += phy-rockchip-pcie.o
obj-$(CONFIG_PHY_ROCKCHIP_SNPS_PCIE3) += phy-rockchip-snps-pcie3.o
obj-$(CONFIG_PHY_ROCKCHIP_TYPEC) += phy-rockchip-typec.o

View file

@ -0,0 +1,157 @@
// SPDX-License-Identifier: GPL-2.0
/*
* Rockchip PCIE3.0 phy driver
*
* Copyright (C) 2021 Rockchip Electronics Co., Ltd.
*/
#include <common.h>
#include <clk.h>
#include <dm.h>
#include <generic-phy.h>
#include <regmap.h>
#include <reset-uclass.h>
#include <syscon.h>
#include <asm/io.h>
#include <dm/device_compat.h>
#include <dm/lists.h>
#define GRF_PCIE30PHY_CON1 0x4
#define GRF_PCIE30PHY_CON6 0x18
#define GRF_PCIE30PHY_CON9 0x24
/**
* struct rockchip_p3phy_priv - RK DW PCIe PHY state
*
* @mmio: The base address of PHY internal registers
* @phy_grf: The regmap for controlling pipe signal
* @p30phy: The reset signal for PHY
* @ref_clk_m: The reference clock of M for PHY
* @ref_clk_n: The reference clock of N for PHY
* @pclk: The clock for accessing PHY blocks
*/
struct rockchip_p3phy_priv {
void __iomem *mmio;
struct regmap *phy_grf;
struct reset_ctl p30phy;
struct clk ref_clk_m;
struct clk ref_clk_n;
struct clk pclk;
};
static int rochchip_p3phy_init(struct phy *phy)
{
struct rockchip_p3phy_priv *priv = dev_get_priv(phy->dev);
int ret;
ret = clk_enable(&priv->ref_clk_m);
if (ret < 0 && ret != -ENOSYS)
return ret;
ret = clk_enable(&priv->ref_clk_n);
if (ret < 0 && ret != -ENOSYS)
goto err_ref;
ret = clk_enable(&priv->pclk);
if (ret < 0 && ret != -ENOSYS)
goto err_pclk;
reset_assert(&priv->p30phy);
udelay(1);
/* Deassert PCIe PMA output clamp mode */
regmap_write(priv->phy_grf, GRF_PCIE30PHY_CON9,
(0x1 << 15) | (0x1 << 31));
reset_deassert(&priv->p30phy);
udelay(1);
return 0;
err_pclk:
clk_disable(&priv->ref_clk_n);
err_ref:
clk_disable(&priv->ref_clk_m);
return ret;
}
static int rochchip_p3phy_exit(struct phy *phy)
{
struct rockchip_p3phy_priv *priv = dev_get_priv(phy->dev);
clk_disable(&priv->ref_clk_m);
clk_disable(&priv->ref_clk_n);
clk_disable(&priv->pclk);
reset_assert(&priv->p30phy);
return 0;
}
static int rockchip_p3phy_probe(struct udevice *dev)
{
struct rockchip_p3phy_priv *priv = dev_get_priv(dev);
struct udevice *syscon;
int ret;
priv->mmio = (void __iomem *)dev_read_addr(dev);
if ((fdt_addr_t)priv->mmio == FDT_ADDR_T_NONE)
return -EINVAL;
ret = uclass_get_device_by_phandle(UCLASS_SYSCON, dev,
"rockchip,phy-grf", &syscon);
if (ret) {
pr_err("unable to find syscon device for rockchip,phy-grf\n");
return ret;
}
priv->phy_grf = syscon_get_regmap(syscon);
if (IS_ERR(priv->phy_grf)) {
dev_err(dev, "failed to find rockchip,phy_grf regmap\n");
return PTR_ERR(priv->phy_grf);
}
ret = reset_get_by_name(dev, "phy", &priv->p30phy);
if (ret) {
dev_err(dev, "no phy reset control specified\n");
return ret;
}
ret = clk_get_by_name(dev, "refclk_m", &priv->ref_clk_m);
if (ret) {
dev_err(dev, "failed to find ref clock M\n");
return PTR_ERR(&priv->ref_clk_m);
}
ret = clk_get_by_name(dev, "refclk_n", &priv->ref_clk_n);
if (ret) {
dev_err(dev, "failed to find ref clock N\n");
return PTR_ERR(&priv->ref_clk_n);
}
ret = clk_get_by_name(dev, "pclk", &priv->pclk);
if (ret) {
dev_err(dev, "failed to find pclk\n");
return PTR_ERR(&priv->pclk);
}
return 0;
}
static struct phy_ops rochchip_p3phy_ops = {
.init = rochchip_p3phy_init,
.exit = rochchip_p3phy_exit,
};
static const struct udevice_id rockchip_p3phy_of_match[] = {
{ .compatible = "rockchip,rk3568-pcie3-phy" },
{ },
};
U_BOOT_DRIVER(rockchip_pcie3phy) = {
.name = "rockchip_pcie3phy",
.id = UCLASS_PHY,
.of_match = rockchip_p3phy_of_match,
.ops = &rochchip_p3phy_ops,
.probe = rockchip_p3phy_probe,
.priv_auto = sizeof(struct rockchip_p3phy_priv),
};