- Assorted platform and video driver updates
This commit is contained in:
Tom Rini 2026-02-25 08:49:28 -06:00
commit 7995bf8dea
11 changed files with 550 additions and 239 deletions

View File

@ -0,0 +1,26 @@
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (c) 2026 Kaustabh Chakraborty <kauschluss@disroot.org>
*/
/ {
/* These properties are required by S-BOOT. */
model_info-chip = <7870>;
model_info-hw_rev = <0>;
model_info-hw_rev_end = <255>;
chosen {
#address-cells = <2>;
#size-cells = <1>;
ranges;
framebuffer@67000000 {
compatible = "simple-framebuffer";
reg = <0x0 0x67000000 (540 * 960 * 4)>;
width = <540>;
height = <960>;
stride = <(540 * 4)>;
format = "a8r8g8b8";
};
};
};

View File

@ -0,0 +1,46 @@
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (c) Kaustabh Chakraborty <kauschluss@disroot.org>
*/
/ {
/* These properties are required by S-BOOT. */
model_info-chip = <7870>;
model_info-hw_rev = <0>;
model_info-hw_rev_end = <255>;
chosen {
#address-cells = <2>;
#size-cells = <1>;
ranges;
framebuffer@67000000 {
compatible = "simple-framebuffer";
reg = <0x0 0x67000000 (720 * 1480 * 4)>;
width = <720>;
height = <1480>;
stride = <(720 * 4)>;
format = "a8r8g8b8";
};
};
/*
* S-BOOT will populate the memory nodes stated below. Existing
* values redefine the safe memory requirements as stated in upstream
* device tree, in separate nodes for each bank.
*/
memory@40000000 {
device_type = "memory";
reg = <0x0 0x40000000 0x3d800000>;
};
memory@80000000 {
device_type = "memory";
reg = <0x0 0x80000000 0x40000000>;
};
memory@100000000 {
device_type = "memory";
reg = <0x1 0x00000000 0x00000000>;
};
};

View File

@ -0,0 +1,41 @@
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (c) 2026 Kaustabh Chakraborty <kauschluss@disroot.org>
*/
/ {
/* These properties are required by S-BOOT. */
model_info-chip = <7870>;
model_info-hw_rev = <0>;
model_info-hw_rev_end = <255>;
chosen {
#address-cells = <2>;
#size-cells = <1>;
ranges;
framebuffer@67000000 {
compatible = "simple-framebuffer";
reg = <0x0 0x67000000 (1080 * 1920 * 4)>;
width = <1080>;
height = <1920>;
stride = <(1080 * 4)>;
format = "a8r8g8b8";
};
};
/*
* S-BOOT will populate the memory nodes stated below. Existing
* values redefine the safe memory requirements as stated in upstream
* device tree, in separate nodes for each bank.
*/
memory@40000000 {
device_type = "memory";
reg = <0x0 0x40000000 0x3e400000>;
};
memory@80000000 {
device_type = "memory";
reg = <0x0 0x80000000 0x80000000>;
};
};

View File

@ -10,30 +10,33 @@
#include <bootflow.h>
#include <ctype.h>
#include <dm/ofnode.h>
#include <efi.h>
#include <efi_loader.h>
#include <env.h>
#include <errno.h>
#include <init.h>
#include <limits.h>
#include <linux/sizes.h>
#include <lmb.h>
#include <part.h>
#include <stdbool.h>
#include <string.h>
DECLARE_GLOBAL_DATA_PTR;
#define lmb_alloc(size, addr) \
lmb_alloc_mem(LMB_MEM_ALLOC_ANY, SZ_2M, addr, size, LMB_NONE)
struct exynos_board_info {
const char *name;
const char *chip;
const u64 *const dram_bank_bases;
struct efi_fw_image fw_images[] = {
{
.fw_name = u"UBOOT_BOOT_PARTITION",
.image_index = 1,
},
};
char serial[64];
int (*const match)(struct exynos_board_info *);
const char *match_model;
const u8 match_max_rev;
struct efi_capsule_update_info update_info = {
.dfu_string = NULL,
.images = fw_images,
.num_images = ARRAY_SIZE(fw_images),
};
/*
@ -54,10 +57,6 @@ static struct mm_region exynos_mem_map[CONFIG_NR_DRAM_BANKS + 2] = {
struct mm_region *mem_map = exynos_mem_map;
static const u64 exynos7870_common_dram_bank_bases[CONFIG_NR_DRAM_BANKS] = {
0x40000000, 0x80000000, 0x100000000,
};
static const char *exynos_prev_bl_get_bootargs(void)
{
void *prev_bl_fdt_base = (void *)get_prev_bl_fdt_addr();
@ -89,102 +88,11 @@ static const char *exynos_prev_bl_get_bootargs(void)
return bootargs_prop->data;
}
static int exynos7870_fdt_match(struct exynos_board_info *board_info)
{
const char *prev_bl_bootargs;
int val, ret;
prev_bl_bootargs = exynos_prev_bl_get_bootargs();
if (!prev_bl_bootargs)
return -1;
/*
* Read the cmdline property which stores the
* bootloader/firmware version. An example value of the option
* can be: "J600GDXU3ARH5". This can be used to verify the model
* of the device.
*/
ret = cmdline_get_arg(prev_bl_bootargs, "androidboot.bootloader", &val);
if (ret < 0) {
log_err("%s: unable to find property for bootloader version (%d)\n",
__func__, ret);
return -1;
}
if (strncmp(prev_bl_bootargs + val, board_info->match_model,
strlen(board_info->match_model)))
return -1;
/*
* Read the cmdline property which stores the hardware revision.
* This is required to allow selecting one of multiple dtbs
* available of a single device, varying in hardware changes in
* different revisions.
*/
ret = cmdline_get_arg(prev_bl_bootargs, "androidboot.revision", &val);
if (ret < 0)
ret = cmdline_get_arg(prev_bl_bootargs, "androidboot.hw_rev", &val);
if (ret < 0) {
log_err("%s: unable to find property for bootloader revision (%d)\n",
__func__, ret);
return -1;
}
if (strtoul(prev_bl_bootargs + val, NULL, 10) > board_info->match_max_rev)
return -1;
/*
* Read the cmdline property which stores the serial number.
* Store this in the board info struct.
*/
ret = cmdline_get_arg(prev_bl_bootargs, "androidboot.serialno", &val);
if (ret > 0)
strlcpy(board_info->serial, prev_bl_bootargs + val, ret);
return 0;
}
/*
* This array is used for matching the models and revisions with the
* devicetree used by U-Boot. This allows a single U-Boot to work on
* multiple devices.
*
* Entries are kept in lexicographical order of board SoCs, followed by
* board names.
*/
static struct exynos_board_info exynos_board_info_match[] = {
{
/* Samsung Galaxy A2 Core */
.name = "a2corelte",
.chip = "exynos7870",
.dram_bank_bases = exynos7870_common_dram_bank_bases,
.match = exynos7870_fdt_match,
.match_model = "A260",
.match_max_rev = U8_MAX,
}, {
/* Samsung Galaxy J6 */
.name = "j6lte",
.chip = "exynos7870",
.dram_bank_bases = exynos7870_common_dram_bank_bases,
.match = exynos7870_fdt_match,
.match_model = "J600",
.match_max_rev = U8_MAX,
}, {
/* Samsung Galaxy J7 Prime */
.name = "on7xelte",
.chip = "exynos7870",
.dram_bank_bases = exynos7870_common_dram_bank_bases,
.match = exynos7870_fdt_match,
.match_model = "G610",
.match_max_rev = U8_MAX,
},
};
static void exynos_parse_dram_banks(const struct exynos_board_info *board_info,
const void *fdt_base)
static void exynos_parse_dram_banks(const void *fdt_base)
{
u64 mem_addr, mem_size = 0;
u32 na, ns, i, j;
u32 na, ns, i;
int index = 1;
int offset;
if (fdt_check_header(fdt_base) < 0)
@ -199,6 +107,9 @@ static void exynos_parse_dram_banks(const struct exynos_board_info *board_info,
continue;
for (i = 0; ; i++) {
if (index > CONFIG_NR_DRAM_BANKS)
break;
mem_addr = fdtdec_get_addr_size_fixed(fdt_base, offset,
"reg", i, na, ns,
&mem_size, false);
@ -208,21 +119,134 @@ static void exynos_parse_dram_banks(const struct exynos_board_info *board_info,
if (!mem_size)
continue;
for (j = 0; j < CONFIG_NR_DRAM_BANKS; j++) {
if (board_info->dram_bank_bases[j] != mem_addr)
continue;
mem_map[j + 1].phys = mem_addr;
mem_map[j + 1].virt = mem_addr;
mem_map[j + 1].size = mem_size;
mem_map[j + 1].attrs = PTE_BLOCK_MEMTYPE(MT_NORMAL) |
PTE_BLOCK_INNER_SHARE;
break;
}
mem_map[index].phys = mem_addr;
mem_map[index].virt = mem_addr;
mem_map[index].size = mem_size;
mem_map[index].attrs = PTE_BLOCK_MEMTYPE(MT_NORMAL) |
PTE_BLOCK_INNER_SHARE;
index++;
}
}
}
static void exynos_env_setup(void)
{
const char *bootargs = exynos_prev_bl_get_bootargs();
const char *dev_compatible, *soc_compatible;
char *ptr;
char buf[128];
int nr_compatibles;
int offset;
int ret;
if (bootargs) {
/* Read the cmdline property which stores the serial number. */
ret = cmdline_get_arg(bootargs, "androidboot.serialno", &offset);
if (ret > 0) {
strlcpy(buf, bootargs + offset, ret);
env_set("serial#", buf);
}
}
nr_compatibles = ofnode_read_string_count(ofnode_root(), "compatible");
if (nr_compatibles < 2) {
log_warning("%s: expected 2 or more compatible strings\n",
__func__);
return;
}
ret = ofnode_read_string_index(ofnode_root(), "compatible",
nr_compatibles - 1, &soc_compatible);
if (ret) {
log_warning("%s: failed to read SoC compatible\n",
__func__);
return;
}
ret = ofnode_read_string_index(ofnode_root(), "compatible", 0,
&dev_compatible);
if (ret) {
log_warning("%s: failed to read device compatible\n",
__func__);
return;
}
/* <manufacturer>,<soc> => platform = <soc> */
ptr = strchr(soc_compatible, ',');
if (ptr)
soc_compatible = ptr + 1;
env_set("platform", soc_compatible);
/* <manufacturer>,<codename> => board = <manufacturer>-<codename> */
strlcpy(buf, dev_compatible, sizeof(buf) - 1);
ptr = strchr(buf, ',');
if (ptr)
*ptr = '-';
env_set("board", buf);
/*
* NOTE: Board name usually goes as <manufacturer>-<codename>, but
* upstream device trees for Exynos SoCs are <soc>-<codename>.
* Extraction of <codename> from the board name is required.
*/
ptr = strchr(dev_compatible, ',');
if (ptr)
dev_compatible = ptr + 1;
/* EFI booting requires the path to correct DTB, specify it here. */
snprintf(buf, sizeof(buf), "exynos/%s-%s.dtb", soc_compatible,
dev_compatible);
env_set("fdtfile", buf);
}
static int exynos_blk_env_setup(void)
{
const char *blk_ifname;
int blk_dev = 0;
struct blk_desc *blk_desc;
struct disk_partition info = {0};
unsigned long largest_part_start = 0, largest_part_size = 0;
static char dfu_string[32];
int i;
blk_ifname = "mmc";
blk_desc = blk_get_dev(blk_ifname, blk_dev);
if (!blk_desc) {
log_err("%s: required mmc device not available\n", __func__);
return -ENODEV;
}
for (i = 1; i < CONFIG_EFI_PARTITION_ENTRIES_NUMBERS; i++) {
if (part_get_info(blk_desc, i, &info))
continue;
if (!update_info.dfu_string &&
!strncasecmp(info.name, "boot", strlen("boot"))) {
snprintf(dfu_string, sizeof(dfu_string),
"mmc %d=u-boot.bin part %d %d", blk_dev,
blk_dev, i);
update_info.dfu_string = dfu_string;
}
if (info.start > largest_part_size) {
largest_part_start = info.start;
largest_part_size = info.size;
}
}
if (largest_part_size) {
env_set("blkmap_blk_ifname", blk_ifname);
env_set_ulong("blkmap_blk_dev", blk_dev);
env_set_ulong("blkmap_blk_nr", largest_part_start);
env_set_hex("blkmap_size_r", largest_part_size);
} else {
log_warning("%s: no qualified partition for blkmap, skipping\n",
__func__);
}
return 0;
}
static int exynos_fastboot_setup(void)
{
struct blk_desc *blk_dev;
@ -270,42 +294,11 @@ static int exynos_fastboot_setup(void)
return 0;
}
int board_fit_config_name_match(const char *name)
int board_fdt_blob_setup(void **fdtp)
{
struct exynos_board_info *board_info;
char buf[128];
unsigned int i;
int ret;
/*
* Iterate over exynos_board_info_match[] to select the
* appropriate board info struct. If not found, exit.
*/
for (i = 0; i < ARRAY_SIZE(exynos_board_info_match); i++) {
board_info = exynos_board_info_match + i;
snprintf(buf, sizeof(buf), "%s-%s", board_info->chip,
board_info->name);
if (!strcmp(name, buf))
break;
}
if (i == ARRAY_SIZE(exynos_board_info_match))
return -1;
/*
* Execute match logic for the target board. This is separated
* as the process may be different for multiple boards.
*/
ret = board_info->match(board_info);
if (ret)
return ret;
/*
* Store the correct board info struct in gd->board_type to
* allow other functions to access it.
*/
gd->board_type = (ulong)board_info;
log_debug("%s: device detected: %s\n", __func__, name);
/* If internal FDT is not available, use the external FDT instead. */
if (fdt_check_header(*fdtp))
*fdtp = (void *)get_prev_bl_fdt_addr();
return 0;
}
@ -328,21 +321,7 @@ int timer_init(void)
int board_early_init_f(void)
{
const struct exynos_board_info *board_info;
if (!gd->board_type)
return -ENODATA;
board_info = (const struct exynos_board_info *)gd->board_type;
exynos_parse_dram_banks(board_info, gd->fdt_blob);
/*
* Some devices have multiple variants based on the amount of
* memory and internal storage. The lowest bank base has been
* observed to have the same memory range in all board variants.
* For variants with more memory, the previous bootloader should
* overlay the devicetree with the required extra memory ranges.
*/
exynos_parse_dram_banks(board_info, (const void *)get_prev_bl_fdt_addr());
exynos_parse_dram_banks(gd->fdt_blob);
return 0;
}
@ -381,23 +360,13 @@ int board_init(void)
int misc_init_r(void)
{
const struct exynos_board_info *board_info;
char buf[128];
int ret;
if (!gd->board_type)
return -ENODATA;
board_info = (const struct exynos_board_info *)gd->board_type;
exynos_env_setup();
env_set("platform", board_info->chip);
env_set("board", board_info->name);
if (strlen(board_info->serial))
env_set("serial#", board_info->serial);
/* EFI booting requires the path to correct dtb, specify it here. */
snprintf(buf, sizeof(buf), "exynos/%s-%s.dtb", board_info->chip,
board_info->name);
env_set("fdtfile", buf);
ret = exynos_blk_env_setup();
if (ret)
return ret;
return exynos_fastboot_setup();
}

View File

@ -2,6 +2,11 @@ stdin=serial,button-kbd
stdout=serial,vidconsole
stderr=serial,vidconsole
blkmapcmd=blkmap create root;
blkmap map root 0 ${blkmap_size_r} linear ${blkmap_blk_ifname} ${blkmap_blk_dev} ${blkmap_blk_nr}
preboot=run blkmapcmd
bootdelay=0
bootcmd=bootefi bootmgr; pause; bootmenu

View File

@ -12,7 +12,12 @@ CONFIG_SYS_BOOTM_LEN=0x2000000
CONFIG_SYS_LOAD_ADDR=0x80000000
CONFIG_ARMV8_CNTFRQ_BROKEN=y
# CONFIG_PSCI_RESET is not set
CONFIG_EFI_RUNTIME_UPDATE_CAPSULE=y
CONFIG_EFI_CAPSULE_ON_DISK=y
CONFIG_EFI_CAPSULE_ON_DISK_EARLY=y
CONFIG_EFI_CAPSULE_FIRMWARE_RAW=y
CONFIG_BUTTON_CMD=y
CONFIG_USE_PREBOOT=y
CONFIG_SAVE_PREV_BL_FDT_ADDR=y
CONFIG_SAVE_PREV_BL_INITRAMFS_START_ADDR=y
CONFIG_SYS_PBSIZE=1024
@ -25,11 +30,14 @@ CONFIG_CMD_POWEROFF=y
CONFIG_CMD_FS_GENERIC=y
CONFIG_EFI_PARTITION=y
CONFIG_OF_UPSTREAM=y
CONFIG_OF_LIST="exynos/exynos7870-a2corelte exynos/exynos7870-j6lte exynos/exynos7870-on7xelte"
CONFIG_MULTI_DTB_FIT=y
CONFIG_OF_UPSTREAM_BUILD_VENDOR=y
CONFIG_OF_BOARD=y
CONFIG_BLKMAP=y
CONFIG_BUTTON=y
CONFIG_BUTTON_REMAP_PHONE_KEYS=y
CONFIG_CLK_EXYNOS7870=y
CONFIG_DFU_MMC=y
CONFIG_SYS_DFU_DATA_BUF_SIZE=0x200000
CONFIG_USB_FUNCTION_FASTBOOT=y
CONFIG_FASTBOOT_BUF_ADDR=0xdead0000
CONFIG_FASTBOOT_FLASH=y

View File

@ -25,12 +25,13 @@ If a cross-compiler is required, install it and set it up like so:
export CROSS_COMPILE=aarch64-linux-gnu-
Then, run the following commands to build U-Boot:
Then, run the following commands to build U-Boot (replace ``<dtb>`` with the
upstream DTB path for the target device):
.. prompt:: bash $
make O=.output exynos-mobile_defconfig
make O=.output -j$(nproc)
make DEVICE_TREE=<dtb> O=.output -j$(nproc)
If successful, the U-Boot binary will be present in ``.output/u-boot.bin``.

View File

@ -6,54 +6,20 @@ Samsung Exynos 7870 Boards
Preparation
-----------
Create the following device tree (named ``stub.dts``)
.. code-block:: devicetree
/dts-v1/;
/ {
compatible = "samsung,exynos7870";
#address-cells = <2>;
#size-cells = <1>;
model_info-chip = <7870>;
model_info-hw_rev = <0>;
model_info-hw_rev_end = <255>;
chosen {
};
memory@80000000 {
device_type = "memory";
reg = <0x0 0x80000000 0x0>;
};
memory@100000000 {
device_type = "memory";
reg = <0x1 0x00000000 0x0>;
};
};
The chosen node and memory ranges are populated by S-BOOT. A certain device
model may have multiple variants, with differing amounts of RAM and storage. The
RAM capacity information is graciously provided by S-BOOT's device tree
overlays.
Compile it to a device tree blob, then pack it in the QCDT format [1]_ using
``dtbTool-exynos`` [2]_ by issuing the following commands:
Pack the device tree blob in the QCDT format [1]_ using ``dtbTool-exynos`` [2]_
by issuing the following commands:
.. prompt:: bash $
dtc -I dts -O dtb -o stub.dtb stub.dts
dtbTool-exynos -o stub-dt.img stub.dtb
dtbTool-exynos -o stub-dt.img .output/u-boot.dtb
Finally, use ``mkbootimg`` by osm0sis [3]_ to generate the boot image:
.. prompt:: bash $
mkbootimg -o u-boot.img \
--kernel .output/u-boot.bin \
--kernel .output/u-boot-nodtb.bin \
--dt stub-dt.img
Offsets are not provided to ``mkbootimg`` as S-BOOT ignores them.

View File

@ -21,6 +21,7 @@
/* Offset of PMU register controlling USB PHY output isolation */
#define EXYNOS_USBDRD_PHY_CONTROL 0x0704
#define EXYNOS_PHY_ENABLE BIT(0)
#define EXYNOS7870_PHY_ENABLE BIT(1)
/* Exynos USB PHY registers */
#define EXYNOS5_FSEL_9MHZ6 0x0
@ -32,6 +33,88 @@
#define EXYNOS5_FSEL_26MHZ 0x6
#define EXYNOS5_FSEL_50MHZ 0x7
/* Exynos5: USB DRD PHY registers */
#define EXYNOS5_DRD_LINKSYSTEM 0x04
#define LINKSYSTEM_XHCI_VERSION_CONTROL BIT(27)
#define LINKSYSTEM_FORCE_VBUSVALID BIT(8)
#define LINKSYSTEM_FORCE_BVALID BIT(7)
#define LINKSYSTEM_FLADJ GENMASK(6, 1)
#define EXYNOS5_DRD_PHYUTMI 0x08
#define PHYUTMI_UTMI_SUSPEND_COM_N BIT(12)
#define PHYUTMI_UTMI_L1_SUSPEND_COM_N BIT(11)
#define PHYUTMI_VBUSVLDEXTSEL BIT(10)
#define PHYUTMI_VBUSVLDEXT BIT(9)
#define PHYUTMI_TXBITSTUFFENH BIT(8)
#define PHYUTMI_TXBITSTUFFEN BIT(7)
#define PHYUTMI_OTGDISABLE BIT(6)
#define PHYUTMI_IDPULLUP BIT(5)
#define PHYUTMI_DRVVBUS BIT(4)
#define PHYUTMI_DPPULLDOWN BIT(3)
#define PHYUTMI_DMPULLDOWN BIT(2)
#define PHYUTMI_FORCESUSPEND BIT(1)
#define PHYUTMI_FORCESLEEP BIT(0)
#define EXYNOS5_DRD_PHYCLKRST 0x10
#define PHYCLKRST_EN_UTMISUSPEND BIT(31)
#define PHYCLKRST_SSC_REFCLKSEL GENMASK(30, 23)
#define PHYCLKRST_SSC_RANGE GENMASK(22, 21)
#define PHYCLKRST_SSC_EN BIT(20)
#define PHYCLKRST_REF_SSP_EN BIT(19)
#define PHYCLKRST_REF_CLKDIV2 BIT(18)
#define PHYCLKRST_MPLL_MULTIPLIER GENMASK(17, 11)
#define PHYCLKRST_MPLL_MULTIPLIER_100MHZ_REF 0x19
#define PHYCLKRST_MPLL_MULTIPLIER_50M_REF 0x32
#define PHYCLKRST_MPLL_MULTIPLIER_24MHZ_REF 0x68
#define PHYCLKRST_MPLL_MULTIPLIER_20MHZ_REF 0x7d
#define PHYCLKRST_MPLL_MULTIPLIER_19200KHZ_REF 0x02
#define PHYCLKRST_FSEL_PIPE GENMASK(10, 8)
#define PHYCLKRST_FSEL_UTMI GENMASK(7, 5)
#define PHYCLKRST_FSEL_PAD_100MHZ 0x27
#define PHYCLKRST_FSEL_PAD_24MHZ 0x2a
#define PHYCLKRST_FSEL_PAD_20MHZ 0x31
#define PHYCLKRST_FSEL_PAD_19_2MHZ 0x38
#define PHYCLKRST_RETENABLEN BIT(4)
#define PHYCLKRST_REFCLKSEL GENMASK(3, 2)
#define PHYCLKRST_REFCLKSEL_PAD_REFCLK 0x2
#define PHYCLKRST_REFCLKSEL_EXT_REFCLK 0x3
#define PHYCLKRST_PORTRESET BIT(1)
#define PHYCLKRST_COMMONONN BIT(0)
#define EXYNOS5_DRD_PHYPARAM0 0x1c
#define PHYPARAM0_REF_USE_PAD BIT(31)
#define PHYPARAM0_REF_LOSLEVEL GENMASK(30, 26)
#define PHYPARAM0_REF_LOSLEVEL_VAL 0x9
#define PHYPARAM0_TXVREFTUNE GENMASK(25, 22)
#define PHYPARAM0_TXRISETUNE GENMASK(21, 20)
#define PHYPARAM0_TXRESTUNE GENMASK(19, 18)
#define PHYPARAM0_TXPREEMPPULSETUNE BIT(17)
#define PHYPARAM0_TXPREEMPAMPTUNE GENMASK(16, 15)
#define PHYPARAM0_TXHSXVTUNE GENMASK(14, 13)
#define PHYPARAM0_TXFSLSTUNE GENMASK(12, 9)
#define PHYPARAM0_SQRXTUNE GENMASK(8, 6)
#define PHYPARAM0_OTGTUNE GENMASK(5, 3)
#define PHYPARAM0_COMPDISTUNE GENMASK(2, 0)
#define EXYNOS5_DRD_LINKPORT 0x44
#define LINKPORT_HOST_U3_PORT_DISABLE BIT(8)
#define LINKPORT_HOST_U2_PORT_DISABLE BIT(7)
#define LINKPORT_HOST_PORT_OVCR_U3 BIT(5)
#define LINKPORT_HOST_PORT_OVCR_U2 BIT(4)
#define LINKPORT_HOST_PORT_OVCR_U3_SEL BIT(3)
#define LINKPORT_HOST_PORT_OVCR_U2_SEL BIT(2)
/* Exynos7870: USB DRD PHY registers */
#define EXYNOS7870_DRD_HSPHYCTRL 0x54
#define HSPHYCTRL_PHYSWRSTALL BIT(31)
#define HSPHYCTRL_SIDDQ BIT(6)
#define HSPHYCTRL_PHYSWRST BIT(0)
#define EXYNOS7870_DRD_HSPHYPLLTUNE 0x70
#define HSPHYPLLTUNE_PLL_B_TUNE BIT(6)
#define HSPHYPLLTUNE_PLL_I_TUNE GENMASK(5, 4)
#define HSPHYPLLTUNE_PLL_P_TUNE GENMASK(3, 0)
/* Exynos850: USB DRD PHY registers */
#define EXYNOS850_DRD_LINKCTRL 0x04
#define LINKCTRL_FORCE_QACT BIT(8)
@ -66,6 +149,11 @@
#define KHZ 1000
#define MHZ (KHZ * KHZ)
enum exynos_usbdrd_phy_variant {
EXYNOS7870_USBDRD_PHY,
EXYNOS850_USBDRD_PHY,
};
/**
* struct exynos_usbdrd_phy - driver data for Exynos USB PHY
* @reg_phy: USB PHY controller register memory base
@ -73,6 +161,7 @@
* @core_clk: core clock for phy (ref clock)
* @reg_pmu: regmap for PMU block
* @extrefclk: frequency select settings when using 'separate reference clocks'
* @variant: ID to uniquely distinguish USB PHY variant
*/
struct exynos_usbdrd_phy {
void __iomem *reg_phy;
@ -80,18 +169,23 @@ struct exynos_usbdrd_phy {
struct clk *core_clk;
struct regmap *reg_pmu;
u32 extrefclk;
enum exynos_usbdrd_phy_variant variant;
};
static void exynos_usbdrd_phy_isol(struct regmap *reg_pmu, bool isolate)
static void exynos_usbdrd_phy_isol(struct exynos_usbdrd_phy *phy_drd,
bool isolate)
{
unsigned int val;
unsigned int mask = EXYNOS_PHY_ENABLE, val;
if (!reg_pmu)
if (!phy_drd->reg_pmu)
return;
val = isolate ? 0 : EXYNOS_PHY_ENABLE;
regmap_update_bits(reg_pmu, EXYNOS_USBDRD_PHY_CONTROL,
EXYNOS_PHY_ENABLE, val);
if (phy_drd->variant == EXYNOS7870_USBDRD_PHY)
mask = EXYNOS7870_PHY_ENABLE;
val = isolate ? 0 : mask;
regmap_update_bits(phy_drd->reg_pmu, EXYNOS_USBDRD_PHY_CONTROL,
mask, val);
}
/*
@ -132,6 +226,111 @@ static unsigned int exynos_rate_to_clk(unsigned long rate, u32 *reg)
return 0;
}
static void exynos7870_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;
reg = readl(regs_base + EXYNOS5_DRD_PHYCLKRST);
/* Use PADREFCLK as ref clock */
reg &= ~PHYCLKRST_REFCLKSEL;
reg |= FIELD_PREP(PHYCLKRST_REFCLKSEL, PHYCLKRST_REFCLKSEL_PAD_REFCLK);
/* Select ref clock rate */
reg &= ~PHYCLKRST_FSEL_UTMI;
reg &= ~PHYCLKRST_FSEL_PIPE;
reg |= FIELD_PREP(PHYCLKRST_FSEL_UTMI, phy_drd->extrefclk);
/* Enable suspend and reset the port */
reg |= PHYCLKRST_EN_UTMISUSPEND;
reg |= PHYCLKRST_COMMONONN;
reg |= PHYCLKRST_PORTRESET;
writel(reg, regs_base + EXYNOS5_DRD_PHYCLKRST);
udelay(10);
/* Clear the port reset bit */
reg &= ~PHYCLKRST_PORTRESET;
writel(reg, regs_base + EXYNOS5_DRD_PHYCLKRST);
/* Change PHY PLL tune value */
reg = readl(regs_base + EXYNOS7870_DRD_HSPHYPLLTUNE);
if (phy_drd->extrefclk == EXYNOS5_FSEL_24MHZ)
reg |= HSPHYPLLTUNE_PLL_B_TUNE;
else
reg &= ~HSPHYPLLTUNE_PLL_B_TUNE;
reg &= ~HSPHYPLLTUNE_PLL_P_TUNE;
reg |= FIELD_PREP(HSPHYPLLTUNE_PLL_P_TUNE, 14);
writel(reg, regs_base + EXYNOS7870_DRD_HSPHYPLLTUNE);
/* High-Speed PHY control */
reg = readl(regs_base + EXYNOS7870_DRD_HSPHYCTRL);
reg &= ~HSPHYCTRL_SIDDQ;
reg &= ~HSPHYCTRL_PHYSWRST;
reg &= ~HSPHYCTRL_PHYSWRSTALL;
writel(reg, regs_base + EXYNOS7870_DRD_HSPHYCTRL);
udelay(500);
reg = readl(regs_base + EXYNOS5_DRD_LINKSYSTEM);
/*
* Setting the Frame length Adj value[6:1] to default 0x20
* See xHCI 1.0 spec, 5.2.4
*/
reg |= LINKSYSTEM_XHCI_VERSION_CONTROL;
reg &= ~LINKSYSTEM_FLADJ;
reg |= FIELD_PREP(LINKSYSTEM_FLADJ, 0x20);
/* Set VBUSVALID signal as the VBUS pad is not used */
reg |= LINKSYSTEM_FORCE_BVALID;
reg |= LINKSYSTEM_FORCE_VBUSVALID;
writel(reg, regs_base + EXYNOS5_DRD_LINKSYSTEM);
reg = readl(regs_base + EXYNOS5_DRD_PHYUTMI);
/* Release force_sleep & force_suspend */
reg &= ~PHYUTMI_FORCESLEEP;
reg &= ~PHYUTMI_FORCESUSPEND;
/* DP/DM pull down control */
reg &= ~PHYUTMI_DMPULLDOWN;
reg &= ~PHYUTMI_DPPULLDOWN;
reg &= ~PHYUTMI_DRVVBUS;
/* Set DP-pull up as the VBUS pad is not used */
reg |= PHYUTMI_VBUSVLDEXTSEL;
reg |= PHYUTMI_VBUSVLDEXT;
/* Disable OTG block and VBUS valid comparator */
reg |= PHYUTMI_OTGDISABLE;
writel(reg, regs_base + EXYNOS5_DRD_PHYUTMI);
/* Configure OVC IO usage */
reg = readl(regs_base + EXYNOS5_DRD_LINKPORT);
reg |= LINKPORT_HOST_PORT_OVCR_U3_SEL | LINKPORT_HOST_PORT_OVCR_U2_SEL;
writel(reg, regs_base + EXYNOS5_DRD_LINKPORT);
/* High-Speed PHY swrst */
reg = readl(regs_base + EXYNOS7870_DRD_HSPHYCTRL);
reg |= HSPHYCTRL_PHYSWRST;
writel(reg, regs_base + EXYNOS7870_DRD_HSPHYCTRL);
udelay(20);
/* Clear the PHY swrst bit */
reg = readl(regs_base + EXYNOS7870_DRD_HSPHYCTRL);
reg &= ~HSPHYCTRL_PHYSWRST;
writel(reg, regs_base + EXYNOS7870_DRD_HSPHYCTRL);
reg = readl(regs_base + EXYNOS5_DRD_PHYPARAM0);
reg &= ~(PHYPARAM0_TXVREFTUNE | PHYPARAM0_TXRISETUNE |
PHYPARAM0_TXRESTUNE | PHYPARAM0_TXPREEMPPULSETUNE |
PHYPARAM0_TXPREEMPAMPTUNE | PHYPARAM0_TXHSXVTUNE |
PHYPARAM0_TXFSLSTUNE | PHYPARAM0_SQRXTUNE |
PHYPARAM0_OTGTUNE | PHYPARAM0_COMPDISTUNE);
reg |= FIELD_PREP_CONST(PHYPARAM0_TXVREFTUNE, 14) |
FIELD_PREP_CONST(PHYPARAM0_TXRISETUNE, 1) |
FIELD_PREP_CONST(PHYPARAM0_TXRESTUNE, 3) |
FIELD_PREP_CONST(PHYPARAM0_TXPREEMPAMPTUNE, 0) |
FIELD_PREP_CONST(PHYPARAM0_TXHSXVTUNE, 0) |
FIELD_PREP_CONST(PHYPARAM0_TXFSLSTUNE, 3) |
FIELD_PREP_CONST(PHYPARAM0_SQRXTUNE, 6) |
FIELD_PREP_CONST(PHYPARAM0_OTGTUNE, 2) |
FIELD_PREP_CONST(PHYPARAM0_COMPDISTUNE, 3);
writel(reg, regs_base + EXYNOS5_DRD_PHYPARAM0);
}
static void exynos850_usbdrd_utmi_init(struct phy *phy)
{
struct exynos_usbdrd_phy *phy_drd = dev_get_priv(phy->dev);
@ -219,6 +418,33 @@ static void exynos850_usbdrd_utmi_init(struct phy *phy)
writel(reg, regs_base + EXYNOS850_DRD_HSP);
}
static void exynos7870_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;
/*
* Disable the VBUS signal and the ID pull-up resistor.
* Enable force-suspend and force-sleep modes.
*/
reg = readl(regs_base + EXYNOS5_DRD_PHYUTMI);
reg &= ~(PHYUTMI_DRVVBUS | PHYUTMI_VBUSVLDEXT | PHYUTMI_VBUSVLDEXTSEL);
reg &= ~PHYUTMI_IDPULLUP;
reg |= PHYUTMI_FORCESUSPEND | PHYUTMI_FORCESLEEP;
writel(reg, regs_base + EXYNOS5_DRD_PHYUTMI);
/* Power down PHY analog blocks */
reg = readl(regs_base + EXYNOS7870_DRD_HSPHYCTRL);
reg |= HSPHYCTRL_SIDDQ;
writel(reg, regs_base + EXYNOS7870_DRD_HSPHYCTRL);
/* Clear VBUSVALID signal as the VBUS pad is not used */
reg = readl(regs_base + EXYNOS5_DRD_LINKSYSTEM);
reg &= ~(LINKSYSTEM_FORCE_BVALID | LINKSYSTEM_FORCE_VBUSVALID);
writel(reg, regs_base + EXYNOS5_DRD_LINKSYSTEM);
}
static void exynos850_usbdrd_utmi_exit(struct phy *phy)
{
struct exynos_usbdrd_phy *phy_drd = dev_get_priv(phy->dev);
@ -254,7 +480,16 @@ static int exynos_usbdrd_phy_init(struct phy *phy)
if (ret)
return ret;
exynos850_usbdrd_utmi_init(phy);
switch (phy_drd->variant) {
case EXYNOS7870_USBDRD_PHY:
exynos7870_usbdrd_utmi_init(phy);
break;
case EXYNOS850_USBDRD_PHY:
exynos850_usbdrd_utmi_init(phy);
break;
default:
dev_err(phy->dev, "Failed to recognize phy variant\n");
}
clk_disable_unprepare(phy_drd->clk);
@ -270,7 +505,16 @@ static int exynos_usbdrd_phy_exit(struct phy *phy)
if (ret)
return ret;
exynos850_usbdrd_utmi_exit(phy);
switch (phy_drd->variant) {
case EXYNOS7870_USBDRD_PHY:
exynos7870_usbdrd_utmi_exit(phy);
break;
case EXYNOS850_USBDRD_PHY:
exynos850_usbdrd_utmi_exit(phy);
break;
default:
dev_err(phy->dev, "Failed to recognize phy variant\n");
}
clk_disable_unprepare(phy_drd->clk);
@ -289,7 +533,7 @@ static int exynos_usbdrd_phy_power_on(struct phy *phy)
return ret;
/* Power-on PHY */
exynos_usbdrd_phy_isol(phy_drd->reg_pmu, false);
exynos_usbdrd_phy_isol(phy_drd, false);
return 0;
}
@ -301,7 +545,7 @@ static int exynos_usbdrd_phy_power_off(struct phy *phy)
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);
exynos_usbdrd_phy_isol(phy_drd, true);
clk_disable_unprepare(phy_drd->core_clk);
@ -359,6 +603,8 @@ static int exynos_usbdrd_phy_probe(struct udevice *dev)
return err;
}
phy_drd->variant = dev_get_driver_data(dev);
return 0;
}
@ -370,8 +616,13 @@ static const struct phy_ops exynos_usbdrd_phy_ops = {
};
static const struct udevice_id exynos_usbdrd_phy_of_match[] = {
{
.compatible = "samsung,exynos7870-usbdrd-phy",
.data = EXYNOS7870_USBDRD_PHY,
},
{
.compatible = "samsung,exynos850-usbdrd-phy",
.data = EXYNOS850_USBDRD_PHY,
},
{ }
};

View File

@ -350,7 +350,7 @@ void exynos_fimd_window_off(struct exynos_fb_priv *priv, unsigned int win_id)
void exynos_fimd_disable_sysmmu(void)
{
u32 *sysmmufimd;
unsigned int node;
int node;
int node_list[2];
int count;
int i;

View File

@ -1641,8 +1641,6 @@ void nx_mlc_set_layer_alpha256(u32 module_index, u32 layer, u32 alpha)
u32 register_data;
register struct nx_mlc_register_set *pregister;
if (alpha < 0)
alpha = 0;
if (alpha > 255)
alpha = 255;