- Enhanced e850-96 support
This commit is contained in:
Tom Rini 2025-07-25 07:50:44 -06:00
commit 088d24eb96
10 changed files with 637 additions and 13 deletions

View File

@ -602,6 +602,7 @@ ARM SAMSUNG EXYNOS850 SOC
M: Sam Protsenko <semen.protsenko@linaro.org>
S: Maintained
F: drivers/clk/exynos/clk-exynos850.c
F: drivers/phy/phy-exynos-usbdrd.c
F: drivers/pinctrl/exynos/pinctrl-exynos850.c
ARM SAMSUNG SOC DRIVERS

View File

@ -4,9 +4,57 @@
* Author: Sam Protsenko <semen.protsenko@linaro.org>
*/
#include <efi_loader.h>
#include <env.h>
#include <init.h>
#include <mapmem.h>
#include <asm/io.h>
#include "fw.h"
/* OTP Controller base address and register offsets */
#define EXYNOS850_OTP_BASE 0x10000000
#define OTP_CHIPID0 0x4
#define OTP_CHIPID1 0x8
struct efi_fw_image fw_images[] = {
{
.image_type_id = E850_96_FWBL1_IMAGE_GUID,
.fw_name = u"E850-96-FWBL1",
.image_index = 1,
},
{
.image_type_id = E850_96_EPBL_IMAGE_GUID,
.fw_name = u"E850-96-EPBL",
.image_index = 2,
},
{
.image_type_id = E850_96_BL2_IMAGE_GUID,
.fw_name = u"E850-96-BL2",
.image_index = 3,
},
{
.image_type_id = E850_96_BOOTLOADER_IMAGE_GUID,
.fw_name = u"E850-96-BOOTLOADER",
.image_index = 4,
},
{
.image_type_id = E850_96_EL3_MON_IMAGE_GUID,
.fw_name = u"E850-96-EL3-MON",
.image_index = 5,
},
};
struct efi_capsule_update_info update_info = {
.dfu_string = "mmc 0="
"fwbl1.img raw 0x0 0x18 mmcpart 1;"
"epbl.img raw 0x18 0x98 mmcpart 1;"
"bl2.img raw 0xb0 0x200 mmcpart 1;"
"bootloader.img raw 0x438 0x1000 mmcpart 1;"
"el3_mon.img raw 0x1438 0x200 mmcpart 1",
.num_images = ARRAY_SIZE(fw_images),
.images = fw_images,
};
int dram_init(void)
{
return fdtdec_setup_mem_size_base();
@ -17,10 +65,39 @@ int dram_init_banksize(void)
return fdtdec_setup_memory_banksize();
}
/* Read the unique SoC ID from OTP registers */
static u64 get_chip_id(void)
{
void __iomem *otp_base;
u64 val;
otp_base = map_sysmem(EXYNOS850_OTP_BASE, 12);
val = readl(otp_base + OTP_CHIPID0);
val |= (u64)readl(otp_base + OTP_CHIPID1) << 32UL;
unmap_sysmem(otp_base);
return val;
}
static void setup_serial(void)
{
char serial_str[17] = { 0 };
u64 serial_num;
if (env_get("serial#"))
return;
serial_num = get_chip_id();
snprintf(serial_str, sizeof(serial_str), "%016llx", serial_num);
env_set("serial#", serial_str);
}
int board_late_init(void)
{
int err;
setup_serial();
/*
* Do this in board_late_init() to make sure MMC is not probed before
* efi_init_early().

View File

@ -7,5 +7,49 @@ pxefile_addr_r=0x8c200000
ramdisk_addr_r=0x8c300000
fdtfile=CONFIG_DEFAULT_FDT_FILE
dfu_alt_info=
rawemmc raw 0 0x747c000 mmcpart 1;
esp part 0 1;
rootfs part 0 2;
fwbl1 raw 0x0 0x18 mmcpart 1;
epbl raw 0x18 0x98 mmcpart 1;
bl2 raw 0xb0 0x200 mmcpart 1;
dram_train raw 0x2b0 0x20 mmcpart 1;
ect_test raw 0x2d0 0x64 mmcpart 1;
acpm_test raw 0x334 0x104 mmcpart 1;
bootloader raw 0x438 0x1000 mmcpart 1;
el3_mon raw 0x1438 0x200 mmcpart 1
partitions=name=esp,start=512K,size=128M,bootable,type=system;
partitions+=name=rootfs,size=-,bootable,type=linux
partitions_android=name=esp,start=512K,size=128M,bootable,type=system;
partitions_android+=name=efs,size=20M,uuid=${uuid_gpt_efs};
partitions_android+=name=env,size=16K,uuid=${uuid_gpt_env};
partitions_android+=name=kernel,size=30M,uuid=${uuid_gpt_kernel};
partitions_android+=name=ramdisk,size=26M,uuid=${uuid_gpt_ramdisk};
partitions_android+=name=dtbo_a,size=1M,uuid=${uuid_gpt_dtbo};
partitions_android+=name=dtbo_b,size=1M,uuid=${uuid_gpt_dtbo};
partitions_android+=name=ldfw,size=4016K,uuid=${uuid_gpt_ldfw};
partitions_android+=name=keystorage,size=8K,uuid=${uuid_gpt_keystorage};
partitions_android+=name=tzsw,size=1M,uuid=${uuid_gpt_tzsw};
partitions_android+=name=harx,size=2M,uuid=${uuid_gpt_harx};
partitions_android+=name=harx_rkp,size=2M,uuid=${uuid_gpt_harx_rkp};
partitions_android+=name=logo,size=40M,uuid=${uuid_gpt_logo};
partitions_android+=name=super,size=3600M,uuid=${uuid_gpt_super};
partitions_android+=name=cache,size=300M,uuid=${uuid_gpt_cache};
partitions_android+=name=modem,size=100M,uuid=${uuid_gpt_modem};
partitions_android+=name=boot_a,size=100M,uuid=${uuid_gpt_boot};
partitions_android+=name=boot_b,size=100M,uuid=${uuid_gpt_boot};
partitions_android+=name=persist,size=30M,uuid=${uuid_gpt_persist};
partitions_android+=name=recovery_a,size=40M,uuid=${uuid_gpt_recovery};
partitions_android+=name=recovery_b,size=40M,uuid=${uuid_gpt_recovery};
partitions_android+=name=misc,size=40M,uuid=${uuid_gpt_misc};
partitions_android+=name=mnv,size=20M,uuid=${uuid_gpt_mnv};
partitions_android+=name=frp,size=512K,uuid=${uuid_gpt_frp};
partitions_android+=name=vbmeta_a,size=64K,uuid=${uuid_gpt_vbmeta};
partitions_android+=name=vbmeta_b,size=64K,uuid=${uuid_gpt_vbmeta};
partitions_android+=name=metadata,size=16M,uuid=${uuid_gpt_metadata};
partitions_android+=name=dtb_a,size=1M,uuid=${uuid_gpt_dtb};
partitions_android+=name=dtb_b,size=1M,uuid=${uuid_gpt_dtb};
partitions_android+=name=userdata,size=-,uuid=${uuid_gpt_userdata}

View File

@ -3,7 +3,7 @@ CONFIG_ARCH_CPU_INIT=y
CONFIG_ARM_SMCCC=y
CONFIG_ARCH_EXYNOS=y
CONFIG_TEXT_BASE=0xf8800000
CONFIG_SYS_MALLOC_LEN=0x81f000
CONFIG_SYS_MALLOC_LEN=0x2000000
CONFIG_SYS_MALLOC_F_LEN=0x4000
CONFIG_ARCH_EXYNOS9=y
CONFIG_HAS_CUSTOM_SYS_INIT_SP_ADDR=y
@ -15,7 +15,9 @@ CONFIG_SYS_LOAD_ADDR=0x80000000
CONFIG_ENV_OFFSET_REDUND=0x10000
# CONFIG_PSCI_RESET is not set
CONFIG_EFI_SET_TIME=y
CONFIG_ANDROID_BOOT_IMAGE=y
CONFIG_EFI_RUNTIME_UPDATE_CAPSULE=y
CONFIG_EFI_CAPSULE_ON_DISK=y
CONFIG_EFI_CAPSULE_FIRMWARE_RAW=y
CONFIG_BOOTSTD_FULL=y
CONFIG_DEFAULT_FDT_FILE="exynos850-e850-96.dtb"
# CONFIG_DISPLAY_CPUINFO is not set
@ -25,6 +27,7 @@ CONFIG_CMD_BOOTEFI_SELFTEST=y
CONFIG_CMD_ABOOTIMG=y
CONFIG_CMD_NVEDIT_EFI=y
CONFIG_CMD_CLK=y
CONFIG_CMD_DFU=y
CONFIG_CMD_GPT=y
CONFIG_CMD_MMC=y
CONFIG_CMD_EFIDEBUG=y
@ -40,8 +43,18 @@ CONFIG_ENV_RELOC_GD_ENV_ADDR=y
CONFIG_ENV_MMC_EMMC_HW_PARTITION=2
CONFIG_NO_NET=y
CONFIG_CLK_EXYNOS850=y
CONFIG_DFU_MMC=y
CONFIG_USB_FUNCTION_FASTBOOT=y
CONFIG_FASTBOOT_BUF_ADDR=0x8a000000
CONFIG_FASTBOOT_BUF_SIZE=0x30000000
CONFIG_FASTBOOT_FLASH=y
CONFIG_FASTBOOT_FLASH_MMC_DEV=0
CONFIG_FASTBOOT_MMC_BOOT_SUPPORT=y
CONFIG_FASTBOOT_CMD_OEM_FORMAT=y
CONFIG_SUPPORT_EMMC_BOOT=y
CONFIG_MMC_DW=y
CONFIG_PHY=y
CONFIG_PHY_EXYNOS_USBDRD=y
CONFIG_DM_RTC=y
CONFIG_RTC_EMULATION=y
CONFIG_SOC_SAMSUNG=y
@ -49,3 +62,11 @@ CONFIG_EXYNOS_PMU=y
CONFIG_EXYNOS_USI=y
CONFIG_SYSRESET=y
CONFIG_SYSRESET_SYSCON=y
CONFIG_USB=y
CONFIG_DM_USB_GADGET=y
CONFIG_USB_DWC3=y
CONFIG_USB_DWC3_GENERIC=y
CONFIG_USB_GADGET=y
CONFIG_USB_GADGET_MANUFACTURER="Samsung"
CONFIG_USB_GADGET_VENDOR_NUM=0x18d1
CONFIG_USB_GADGET_PRODUCT_NUM=0x0002

View File

@ -43,17 +43,19 @@ Legend:
BL31 in terms of ARM boot flow
* ``LDFW``: Loadable Firmware
Build Procedure
Unbricking Note
---------------
.. warning::
At the moment USB is not enabled in U-Boot for this board. Although eMMC is
enabled, you won't be able to flash images over USB (fastboot). So flashing
U-Boot binary **WILL** effectively brick your board. The ``dltool`` [8]_ can
be used then to perform USB boot and flash LittleKernel bootloader binary [7]_
to unbrick and revive the board. Flashing U-Boot binary might be helpful for
developers or anybody who want to check current state of U-Boot enablement on
E850-96 (which is mostly serial console, eMMC and related blocks).
In case the board is bricked for some reason, the ``dltool`` [8]_ can be used to
unbrick and revive it. This tool performs USB boot, and uploads the LittleKernel
bootloader over USB, which is then being executed on the board. The loaded
bootloader further enters fastboot mode, so that the user can flash the
functional bootloader binary (U-Boot or LittleKernel [7]_) to eMMC using
``fastboot`` tool. Please read the ``dltool`` README file for more details about
the procedure.
Build Procedure
---------------
Build U-Boot binary from source code (using AArch64 baremetal GCC toolchain):
@ -64,8 +66,9 @@ Build U-Boot binary from source code (using AArch64 baremetal GCC toolchain):
make e850-96_defconfig
make
Boot E850-96 board into fastboot mode as described in board software doc [9]_,
and flash U-Boot binary into ``bootloader`` eMMC partition:
The original E850-96 board is shipped with LittleKernel-based bootloader flashed
in eMMC. To replace it with U-Boot, boot into fastboot mode (as described in
the board software documentation [9]_), and flash U-Boot binary:
.. prompt:: bash $
@ -74,6 +77,66 @@ and flash U-Boot binary into ``bootloader`` eMMC partition:
U-Boot will boot up to the shell.
Flashing
--------
User area of eMMC contains GPT partition table (either Linux or Android). Boot
Partition A (``mmc0boot0``) contains all firmware/bootloaders. Boot Partition
B (``mmc0boot1``) contains U-Boot environment.
First make sure to format eMMC accordingly. Prepare the initial environment:
.. prompt:: bash =>
env default -f -a
env save
For Linux, just format eMMC using default ``$partitions`` definitions:
.. prompt:: bash =>
gpt write mmc 0 $partitions
For Android, use ``$partitions_android`` instead:
.. prompt:: bash =>
setenv partitions_linux $partitions
setenv partitions $partitions_android
env save
gpt write mmc 0 $partitions
In case of Linux, there are two partitions available: ``esp`` (EFI System
Partition) and ``rootfs``. It is recommended to use fastboot to flash images to
those partitions. Enter fastboot mode on your device:
.. prompt:: bash =>
fastboot usb 0
And then flash the images:
.. prompt:: bash $
fastboot flash esp esp.img
fastboot flash rootfs rootfs.img
To update the firmware, it's easier to use DFU. Enter DFU mode on the board:
.. prompt:: bash =>
dfu 0 mmc 0
To update U-Boot:
.. prompt:: bash $
dfu-util -D u-boot.bin -a bootloader
It's also possible to use fastboot to flash the whole ``mmc0boot0`` HW
partition, but it's not so straightforward, as one have to prepare the image for
the whole ``boot0`` partition containing all firmware binaries first.
References
----------

View File

@ -259,6 +259,15 @@ config MT76X8_USB_PHY
This PHY is found on MT76x8 devices supporting USB.
config PHY_EXYNOS_USBDRD
bool "Exynos SoC series USB DRD PHY driver"
depends on PHY && CLK
depends on ARCH_EXYNOS
select REGMAP
select SYSCON
help
Enable USB DRD PHY support for Exynos SoC series.
config PHY_MTK_TPHY
bool "MediaTek T-PHY Driver"
depends on PHY

View File

@ -35,6 +35,7 @@ obj-$(CONFIG_KEYSTONE_USB_PHY) += keystone-usb-phy.o
obj-$(CONFIG_MT7620_USB_PHY) += mt7620-usb-phy.o
obj-$(CONFIG_MT76X8_USB_PHY) += mt76x8-usb-phy.o
obj-$(CONFIG_PHY_DA8XX_USB) += phy-da8xx-usb.o
obj-$(CONFIG_PHY_EXYNOS_USBDRD) += phy-exynos-usbdrd.o
obj-$(CONFIG_PHY_MTK_TPHY) += phy-mtk-tphy.o
obj-$(CONFIG_PHY_NPCM_USB) += phy-npcm-usb.o
obj-$(CONFIG_PHY_IMX8MQ_USB) += phy-imx8mq-usb.o

View File

@ -0,0 +1,386 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2025 Linaro Ltd.
* Sam Protsenko <semen.protsenko@linaro.org>
*
* Samsung Exynos SoC series USB DRD PHY driver.
* Based on Linux kernel PHY driver: drivers/phy/samsung/phy-exynos5-usbdrd.c
*/
#include <clk.h>
#include <dm.h>
#include <generic-phy.h>
#include <regmap.h>
#include <syscon.h>
#include <asm/io.h>
#include <dm/device_compat.h>
#include <linux/bitfield.h>
#include <linux/bitops.h>
#include <linux/delay.h>
/* Offset of PMU register controlling USB PHY output isolation */
#define EXYNOS_USBDRD_PHY_CONTROL 0x0704
#define EXYNOS_PHY_ENABLE BIT(0)
/* Exynos USB PHY registers */
#define EXYNOS5_FSEL_9MHZ6 0x0
#define EXYNOS5_FSEL_10MHZ 0x1
#define EXYNOS5_FSEL_12MHZ 0x2
#define EXYNOS5_FSEL_19MHZ2 0x3
#define EXYNOS5_FSEL_20MHZ 0x4
#define EXYNOS5_FSEL_24MHZ 0x5
#define EXYNOS5_FSEL_26MHZ 0x6
#define EXYNOS5_FSEL_50MHZ 0x7
/* Exynos850: USB DRD PHY registers */
#define EXYNOS850_DRD_LINKCTRL 0x04
#define LINKCTRL_FORCE_QACT BIT(8)
#define LINKCTRL_BUS_FILTER_BYPASS GENMASK(7, 4)
#define EXYNOS850_DRD_CLKRST 0x20
#define CLKRST_LINK_SW_RST BIT(0)
#define CLKRST_PORT_RST BIT(1)
#define CLKRST_PHY_SW_RST BIT(3)
#define EXYNOS850_DRD_SSPPLLCTL 0x30
#define SSPPLLCTL_FSEL GENMASK(2, 0)
#define EXYNOS850_DRD_UTMI 0x50
#define UTMI_FORCE_SLEEP BIT(0)
#define UTMI_FORCE_SUSPEND BIT(1)
#define UTMI_DM_PULLDOWN BIT(2)
#define UTMI_DP_PULLDOWN BIT(3)
#define UTMI_FORCE_BVALID BIT(4)
#define UTMI_FORCE_VBUSVALID BIT(5)
#define EXYNOS850_DRD_HSP 0x54
#define HSP_COMMONONN BIT(8)
#define HSP_EN_UTMISUSPEND BIT(9)
#define HSP_VBUSVLDEXT BIT(12)
#define HSP_VBUSVLDEXTSEL BIT(13)
#define HSP_FSV_OUT_EN BIT(24)
#define EXYNOS850_DRD_HSP_TEST 0x5c
#define HSP_TEST_SIDDQ BIT(24)
#define KHZ 1000
#define MHZ (KHZ * KHZ)
/**
* struct exynos_usbdrd_phy - driver data for Exynos USB PHY
* @reg_phy: USB PHY controller register memory base
* @clk: clock for register access
* @core_clk: core clock for phy (ref clock)
* @reg_pmu: regmap for PMU block
* @extrefclk: frequency select settings when using 'separate reference clocks'
*/
struct exynos_usbdrd_phy {
void __iomem *reg_phy;
struct clk *clk;
struct clk *core_clk;
struct regmap *reg_pmu;
u32 extrefclk;
};
static void exynos_usbdrd_phy_isol(struct regmap *reg_pmu, bool isolate)
{
unsigned int val;
if (!reg_pmu)
return;
val = isolate ? 0 : EXYNOS_PHY_ENABLE;
regmap_update_bits(reg_pmu, EXYNOS_USBDRD_PHY_CONTROL,
EXYNOS_PHY_ENABLE, val);
}
/*
* Convert the supplied clock rate to the value that can be written to the PHY
* register.
*/
static unsigned int exynos_rate_to_clk(unsigned long rate, u32 *reg)
{
switch (rate) {
case 9600 * KHZ:
*reg = EXYNOS5_FSEL_9MHZ6;
break;
case 10 * MHZ:
*reg = EXYNOS5_FSEL_10MHZ;
break;
case 12 * MHZ:
*reg = EXYNOS5_FSEL_12MHZ;
break;
case 19200 * KHZ:
*reg = EXYNOS5_FSEL_19MHZ2;
break;
case 20 * MHZ:
*reg = EXYNOS5_FSEL_20MHZ;
break;
case 24 * MHZ:
*reg = EXYNOS5_FSEL_24MHZ;
break;
case 26 * MHZ:
*reg = EXYNOS5_FSEL_26MHZ;
break;
case 50 * MHZ:
*reg = EXYNOS5_FSEL_50MHZ;
break;
default:
return -EINVAL;
}
return 0;
}
static void exynos850_usbdrd_utmi_init(struct phy *phy)
{
struct exynos_usbdrd_phy *phy_drd = dev_get_priv(phy->dev);
void __iomem *regs_base = phy_drd->reg_phy;
u32 reg;
/*
* Disable HWACG (hardware auto clock gating control). This will force
* QACTIVE signal in Q-Channel interface to HIGH level, to make sure
* the PHY clock is not gated by the hardware.
*/
reg = readl(regs_base + EXYNOS850_DRD_LINKCTRL);
reg |= LINKCTRL_FORCE_QACT;
writel(reg, regs_base + EXYNOS850_DRD_LINKCTRL);
/* Start PHY Reset (POR=high) */
reg = readl(regs_base + EXYNOS850_DRD_CLKRST);
reg |= CLKRST_PHY_SW_RST;
writel(reg, regs_base + EXYNOS850_DRD_CLKRST);
/* Enable UTMI+ */
reg = readl(regs_base + EXYNOS850_DRD_UTMI);
reg &= ~(UTMI_FORCE_SUSPEND | UTMI_FORCE_SLEEP | UTMI_DP_PULLDOWN |
UTMI_DM_PULLDOWN);
writel(reg, regs_base + EXYNOS850_DRD_UTMI);
/* Set PHY clock and control HS PHY */
reg = readl(regs_base + EXYNOS850_DRD_HSP);
reg |= HSP_EN_UTMISUSPEND | HSP_COMMONONN;
writel(reg, regs_base + EXYNOS850_DRD_HSP);
/* Set VBUS Valid and D+ pull-up control by VBUS pad usage */
reg = readl(regs_base + EXYNOS850_DRD_LINKCTRL);
reg |= FIELD_PREP(LINKCTRL_BUS_FILTER_BYPASS, 0xf);
writel(reg, regs_base + EXYNOS850_DRD_LINKCTRL);
reg = readl(regs_base + EXYNOS850_DRD_UTMI);
reg |= UTMI_FORCE_BVALID | UTMI_FORCE_VBUSVALID;
writel(reg, regs_base + EXYNOS850_DRD_UTMI);
reg = readl(regs_base + EXYNOS850_DRD_HSP);
reg |= HSP_VBUSVLDEXT | HSP_VBUSVLDEXTSEL;
writel(reg, regs_base + EXYNOS850_DRD_HSP);
reg = readl(regs_base + EXYNOS850_DRD_SSPPLLCTL);
reg &= ~SSPPLLCTL_FSEL;
switch (phy_drd->extrefclk) {
case EXYNOS5_FSEL_50MHZ:
reg |= FIELD_PREP(SSPPLLCTL_FSEL, 7);
break;
case EXYNOS5_FSEL_26MHZ:
reg |= FIELD_PREP(SSPPLLCTL_FSEL, 6);
break;
case EXYNOS5_FSEL_24MHZ:
reg |= FIELD_PREP(SSPPLLCTL_FSEL, 2);
break;
case EXYNOS5_FSEL_20MHZ:
reg |= FIELD_PREP(SSPPLLCTL_FSEL, 1);
break;
case EXYNOS5_FSEL_19MHZ2:
reg |= FIELD_PREP(SSPPLLCTL_FSEL, 0);
break;
default:
dev_warn(phy->dev, "unsupported ref clk: %#.2x\n",
phy_drd->extrefclk);
break;
}
writel(reg, regs_base + EXYNOS850_DRD_SSPPLLCTL);
/* Power up PHY analog blocks */
reg = readl(regs_base + EXYNOS850_DRD_HSP_TEST);
reg &= ~HSP_TEST_SIDDQ;
writel(reg, regs_base + EXYNOS850_DRD_HSP_TEST);
/* Finish PHY reset (POR=low) */
udelay(10); /* required before doing POR=low */
reg = readl(regs_base + EXYNOS850_DRD_CLKRST);
reg &= ~(CLKRST_PHY_SW_RST | CLKRST_PORT_RST);
writel(reg, regs_base + EXYNOS850_DRD_CLKRST);
udelay(75); /* required after POR=low for guaranteed PHY clock */
/* Disable single ended signal out */
reg = readl(regs_base + EXYNOS850_DRD_HSP);
reg &= ~HSP_FSV_OUT_EN;
writel(reg, regs_base + EXYNOS850_DRD_HSP);
}
static void exynos850_usbdrd_utmi_exit(struct phy *phy)
{
struct exynos_usbdrd_phy *phy_drd = dev_get_priv(phy->dev);
void __iomem *regs_base = phy_drd->reg_phy;
u32 reg;
/* Set PHY clock and control HS PHY */
reg = readl(regs_base + EXYNOS850_DRD_UTMI);
reg &= ~(UTMI_DP_PULLDOWN | UTMI_DM_PULLDOWN);
reg |= UTMI_FORCE_SUSPEND | UTMI_FORCE_SLEEP;
writel(reg, regs_base + EXYNOS850_DRD_UTMI);
/* Power down PHY analog blocks */
reg = readl(regs_base + EXYNOS850_DRD_HSP_TEST);
reg |= HSP_TEST_SIDDQ;
writel(reg, regs_base + EXYNOS850_DRD_HSP_TEST);
/* Link reset */
reg = readl(regs_base + EXYNOS850_DRD_CLKRST);
reg |= CLKRST_LINK_SW_RST;
writel(reg, regs_base + EXYNOS850_DRD_CLKRST);
udelay(10); /* required before doing POR=low */
reg &= ~CLKRST_LINK_SW_RST;
writel(reg, regs_base + EXYNOS850_DRD_CLKRST);
}
static int exynos_usbdrd_phy_init(struct phy *phy)
{
struct exynos_usbdrd_phy *phy_drd = dev_get_priv(phy->dev);
int ret;
ret = clk_prepare_enable(phy_drd->clk);
if (ret)
return ret;
exynos850_usbdrd_utmi_init(phy);
clk_disable_unprepare(phy_drd->clk);
return 0;
}
static int exynos_usbdrd_phy_exit(struct phy *phy)
{
struct exynos_usbdrd_phy *phy_drd = dev_get_priv(phy->dev);
int ret;
ret = clk_prepare_enable(phy_drd->clk);
if (ret)
return ret;
exynos850_usbdrd_utmi_exit(phy);
clk_disable_unprepare(phy_drd->clk);
return 0;
}
static int exynos_usbdrd_phy_power_on(struct phy *phy)
{
struct exynos_usbdrd_phy *phy_drd = dev_get_priv(phy->dev);
int ret;
dev_dbg(phy->dev, "Request to power_on usbdrd_phy phy\n");
ret = clk_prepare_enable(phy_drd->core_clk);
if (ret)
return ret;
/* Power-on PHY */
exynos_usbdrd_phy_isol(phy_drd->reg_pmu, false);
return 0;
}
static int exynos_usbdrd_phy_power_off(struct phy *phy)
{
struct exynos_usbdrd_phy *phy_drd = dev_get_priv(phy->dev);
dev_dbg(phy->dev, "Request to power_off usbdrd_phy phy\n");
/* Power-off the PHY */
exynos_usbdrd_phy_isol(phy_drd->reg_pmu, true);
clk_disable_unprepare(phy_drd->core_clk);
return 0;
}
static int exynos_usbdrd_phy_init_clk(struct udevice *dev)
{
struct exynos_usbdrd_phy *phy_drd = dev_get_priv(dev);
unsigned long ref_rate;
int err;
phy_drd->clk = devm_clk_get(dev, "phy");
if (IS_ERR(phy_drd->clk)) {
err = PTR_ERR(phy_drd->clk);
dev_err(dev, "Failed to get phy clock (err=%d)\n", err);
return err;
}
phy_drd->core_clk = devm_clk_get(dev, "ref");
if (IS_ERR(phy_drd->core_clk)) {
err = PTR_ERR(phy_drd->core_clk);
dev_err(dev, "Failed to get ref clock (err=%d)\n", err);
return err;
}
ref_rate = clk_get_rate(phy_drd->core_clk);
err = exynos_rate_to_clk(ref_rate, &phy_drd->extrefclk);
if (err) {
dev_err(dev, "Clock rate %lu not supported\n", ref_rate);
return err;
}
return 0;
}
static int exynos_usbdrd_phy_probe(struct udevice *dev)
{
struct exynos_usbdrd_phy *phy_drd = dev_get_priv(dev);
int err;
phy_drd->reg_phy = dev_read_addr_ptr(dev);
if (!phy_drd->reg_phy)
return -EINVAL;
err = exynos_usbdrd_phy_init_clk(dev);
if (err)
return err;
phy_drd->reg_pmu = syscon_regmap_lookup_by_phandle(dev,
"samsung,pmu-syscon");
if (IS_ERR(phy_drd->reg_pmu)) {
err = PTR_ERR(phy_drd->reg_pmu);
dev_err(dev, "Failed to lookup PMU regmap\n");
return err;
}
return 0;
}
static const struct phy_ops exynos_usbdrd_phy_ops = {
.init = exynos_usbdrd_phy_init,
.exit = exynos_usbdrd_phy_exit,
.power_on = exynos_usbdrd_phy_power_on,
.power_off = exynos_usbdrd_phy_power_off,
};
static const struct udevice_id exynos_usbdrd_phy_of_match[] = {
{
.compatible = "samsung,exynos850-usbdrd-phy",
},
{ }
};
U_BOOT_DRIVER(exynos_usbdrd_phy) = {
.name = "exynos-usbdrd-phy",
.id = UCLASS_PHY,
.of_match = exynos_usbdrd_phy_of_match,
.probe = exynos_usbdrd_phy_probe,
.ops = &exynos_usbdrd_phy_ops,
.priv_auto = sizeof(struct exynos_usbdrd_phy),
};

View File

@ -704,6 +704,7 @@ static const struct udevice_id dwc3_glue_ids[] = {
{ .compatible = "fsl,imx8mp-dwc3", .data = (ulong)&imx8mp_ops },
{ .compatible = "fsl,imx8mq-dwc3" },
{ .compatible = "intel,tangier-dwc3" },
{ .compatible = "samsung,exynos850-dwusb3" },
{ }
};

View File

@ -9,4 +9,25 @@
#ifndef __E850_96_H
#define __E850_96_H
/* GUIDs for capsule updatable firmware images */
#define E850_96_FWBL1_IMAGE_GUID \
EFI_GUID(0x181cd3f2, 0xe375, 0x44d2, 0x80, 0x78, \
0x32, 0x21, 0xe1, 0xdf, 0xb9, 0x5e)
#define E850_96_EPBL_IMAGE_GUID \
EFI_GUID(0x66c1a54d, 0xd149, 0x415d, 0xaa, 0xda, \
0xb8, 0xae, 0xe4, 0x99, 0xb3, 0x70)
#define E850_96_BL2_IMAGE_GUID \
EFI_GUID(0x89471c2a, 0x6c8d, 0x4158, 0xac, 0xad, \
0x23, 0xd3, 0xb2, 0x87, 0x3d, 0x35)
#define E850_96_BOOTLOADER_IMAGE_GUID \
EFI_GUID(0x629578c3, 0xffb3, 0x4a89, 0xac, 0x0c, \
0x61, 0x18, 0x40, 0x72, 0x77, 0x79)
#define E850_96_EL3_MON_IMAGE_GUID \
EFI_GUID(0xdf5718a2, 0x930a, 0x4916, 0xbb, 0x19, \
0x32, 0x13, 0x21, 0x4d, 0x84, 0x86)
#endif /* __E850_96_H */