Merge branch '2021-07-14-platform-updates'

- Assorted platform updates
This commit is contained in:
Tom Rini 2021-07-14 16:48:23 -04:00
commit eae8c7c338
41 changed files with 1682 additions and 254 deletions

View File

@ -118,8 +118,8 @@ F: cmd/arm/
ARM ALTERA SOCFPGA
M: Marek Vasut <marex@denx.de>
M: Simon Goldschmidt <simon.k.r.goldschmidt@gmail.com>
M: Ley Foon Tan <lftan.linux@gmail.com>
S: Maintainted
M: Tien Fong Chee <tien.fong.chee@intel.com>
S: Maintained
T: git https://source.denx.de/u-boot/custodians/u-boot-socfpga.git
F: arch/arm/mach-socfpga/
F: drivers/sysreset/sysreset_socfpga*

View File

@ -254,6 +254,7 @@ dtb-$(CONFIG_ARCH_UNIPHIER_LD11) += \
uniphier-ld11-global.dtb \
uniphier-ld11-ref.dtb
dtb-$(CONFIG_ARCH_UNIPHIER_LD20) += \
uniphier-ld20-akebi96.dtb \
uniphier-ld20-global.dtb \
uniphier-ld20-ref.dtb
dtb-$(CONFIG_ARCH_UNIPHIER_LD4) += \

View File

@ -0,0 +1,189 @@
// SPDX-License-Identifier: GPL-2.0+ OR MIT
//
// Device Tree Source for Akebi96 Development Board
//
// Derived from uniphier-ld20-global.dts.
//
// Copyright (C) 2015-2017 Socionext Inc.
// Copyright (C) 2019-2020 Linaro Ltd.
/dts-v1/;
#include <dt-bindings/gpio/uniphier-gpio.h>
#include "uniphier-ld20.dtsi"
/ {
model = "Akebi96";
compatible = "socionext,uniphier-ld20-akebi96",
"socionext,uniphier-ld20";
chosen {
stdout-path = "serial0:115200n8";
};
aliases {
serial0 = &serial0;
serial1 = &serial1;
serial2 = &serial2;
serial3 = &serial3;
i2c0 = &i2c0;
i2c1 = &i2c1;
i2c2 = &i2c2;
i2c3 = &i2c3;
i2c4 = &i2c4;
i2c5 = &i2c5;
spi0 = &spi0;
spi1 = &spi1;
spi2 = &spi2;
spi3 = &spi3;
ethernet0 = &eth;
};
memory@80000000 {
device_type = "memory";
reg = <0 0x80000000 0 0xc0000000>;
};
framebuffer@c0000000 {
compatible = "simple-framebuffer";
reg = <0 0xc0000000 0 0x02000000>;
width = <1920>;
height = <1080>;
stride = <7680>;
format = "a8r8g8b8";
};
reserved-memory {
#address-cells = <2>;
#size-cells = <2>;
ranges;
memory@c0000000 {
reg = <0 0xc0000000 0 0x02000000>;
no-map;
};
};
sound {
compatible = "audio-graph-card";
label = "UniPhier LD20";
dais = <&spdif_port0
&comp_spdif_port0>;
};
spdif-out {
compatible = "linux,spdif-dit";
#sound-dai-cells = <0>;
port@0 {
spdif_tx: endpoint {
remote-endpoint = <&spdif_hiecout1>;
};
};
};
comp-spdif-out {
compatible = "linux,spdif-dit";
#sound-dai-cells = <0>;
port@0 {
comp_spdif_tx: endpoint {
remote-endpoint = <&comp_spdif_hiecout1>;
};
};
};
firmware {
optee {
compatible = "linaro,optee-tz";
method = "smc";
};
};
};
&spi3 {
status = "okay";
#address-cells = <1>;
#size-cells = <0>;
usb-over-spi@0 {
compatible = "maxim,max3421-udc";
reg = <0>;
spi-max-frequency = <12500000>;
interrupt-parent = <&gpio>;
interrupt-names = "udc";
interrupts = <0 2>;
};
};
&serial0 {
/* Onboard USB-UART */
status = "okay";
};
&serial2 {
/* LS connector UART1 */
status = "okay";
};
&serial3 {
/* LS connector UART0 */
status = "okay";
};
&spdif_hiecout1 {
remote-endpoint = <&spdif_tx>;
};
&comp_spdif_hiecout1 {
remote-endpoint = <&comp_spdif_tx>;
};
&i2c0 {
/* LS connector I2C0 */
status = "okay";
};
&i2c1 {
/* LS connector I2C1 */
status = "okay";
};
&eth {
status = "okay";
phy-handle = <&ethphy>;
};
&mdio {
ethphy: ethernet-phy@0 {
reg = <0>;
};
};
&usb {
status = "okay";
};
&pcie {
status = "okay";
};
&gpio {
/* IRQs for Max3421 */
xirq0 {
gpio-hog;
gpios = <UNIPHIER_GPIO_IRQ(0) 1>;
input;
};
xirq10 {
gpio-hog;
gpios = <UNIPHIER_GPIO_IRQ(10) 1>;
input;
};
};
&pinctrl_aout1 {
groups = "aout1b";
};
&pinctrl_uart3 {
groups = "uart3", "uart3_ctsrts";
};

View File

@ -10,7 +10,7 @@
#include <common.h>
#define MAX_PIN_NAME_LEN 32
static char pin_name[MAX_PIN_NAME_LEN];
static char pin_name[MAX_PIN_NAME_LEN] __section(".data");
static const char * const msm_pinctrl_pins[] = {
"SDC1_CLK",
"SDC1_CMD",
@ -59,4 +59,3 @@ struct msm_pinctrl_data apq8016_data = {
.get_function_mux = apq8016_get_function_mux,
.get_pin_name = apq8016_get_pin_name,
};

View File

@ -10,7 +10,7 @@
#include <common.h>
#define MAX_PIN_NAME_LEN 32
static char pin_name[MAX_PIN_NAME_LEN];
static char pin_name[MAX_PIN_NAME_LEN] __section(".data");
static const char * const msm_pinctrl_pins[] = {
"SDC1_CLK",
"SDC1_CMD",

View File

@ -8,6 +8,7 @@ choice
config TARGET_STEMMY
bool "Samsung (stemmy) board"
select MISC_INIT_R
help
The Samsung "stemmy" board supports Samsung smartphones released with
the ST-Ericsson NovaThor U8500 SoC, e.g.
@ -15,6 +16,7 @@ config TARGET_STEMMY
- Samsung Galaxy S III mini (GT-I8190) "golden"
- Samsung Galaxy S Advance (GT-I9070) "janice"
- Samsung Galaxy Xcover 2 (GT-S7710) "skomer"
- Samsung Galaxy Ace 2 (GT-I8160) "codina"
and likely others as well (untested).

View File

@ -7,6 +7,7 @@ the ST-Ericsson NovaThor U8500 SoC, e.g.
- Samsung Galaxy S III mini (GT-I8190) "golden"
- Samsung Galaxy S Advance (GT-I9070) "janice"
- Samsung Galaxy Xcover 2 (GT-S7710) "skomer"
- Samsung Galaxy Ace 2 (GT-I8160) "codina"
and likely others as well (untested).

View File

@ -3,18 +3,165 @@
* Copyright (C) 2019 Stephan Gerhold <stephan@gerhold.net>
*/
#include <common.h>
#include <env.h>
#include <init.h>
#include <log.h>
#include <stdlib.h>
#include <asm/global_data.h>
#include <asm/setup.h>
#include <asm/system.h>
DECLARE_GLOBAL_DATA_PTR;
/* Parse atags provided by Samsung bootloader to get available memory */
static ulong fw_mach __section(".data");
static ulong fw_atags __section(".data");
static const struct tag *fw_atags_copy;
static uint fw_atags_size;
void save_boot_params(ulong r0, ulong r1, ulong r2, ulong r3)
{
fw_mach = r1;
fw_atags = r2;
save_boot_params_ret();
}
static const struct tag *fw_atags_get(void)
{
const struct tag *tags = (const struct tag *)fw_atags;
if (tags->hdr.tag != ATAG_CORE) {
log_err("Invalid atags: tag 0x%x at %p\n", tags->hdr.tag, tags);
return NULL;
}
return tags;
}
int dram_init(void)
{
gd->ram_size = get_ram_size(CONFIG_SYS_SDRAM_BASE, CONFIG_SYS_SDRAM_SIZE);
const struct tag *t, *tags = fw_atags_get();
if (!tags)
return -EINVAL;
for_each_tag(t, tags) {
if (t->hdr.tag != ATAG_MEM)
continue;
debug("Memory: %#x-%#x (size %#x)\n", t->u.mem.start,
t->u.mem.start + t->u.mem.size, t->u.mem.size);
gd->ram_size += t->u.mem.size;
}
return 0;
}
int dram_init_banksize(void)
{
const struct tag *t, *tags = fw_atags_get();
unsigned int bank = 0;
if (!tags)
return -EINVAL;
for_each_tag(t, tags) {
if (t->hdr.tag != ATAG_MEM)
continue;
gd->bd->bi_dram[bank].start = t->u.mem.start;
gd->bd->bi_dram[bank].size = t->u.mem.size;
if (++bank == CONFIG_NR_DRAM_BANKS)
break;
}
return 0;
}
int board_init(void)
{
gd->bd->bi_arch_number = fw_mach;
gd->bd->bi_boot_params = fw_atags;
return 0;
}
static void parse_serial(const struct tag_serialnr *serialnr)
{
char serial[17];
if (env_get("serial#"))
return;
sprintf(serial, "%08x%08x", serialnr->high, serialnr->low);
env_set("serial#", serial);
}
/*
* The downstream/vendor kernel (provided by Samsung) uses ATAGS for booting.
* It also requires an extremely long cmdline provided by the primary bootloader
* that is not suitable for booting mainline.
*
* Since downstream is the only user of ATAGS, we emulate the behavior of the
* Samsung bootloader by generating only the initrd atag in U-Boot, and copying
* all other ATAGS as-is from the primary bootloader.
*/
static inline bool skip_atag(u32 tag)
{
return (tag == ATAG_NONE || tag == ATAG_CORE ||
tag == ATAG_INITRD || tag == ATAG_INITRD2);
}
static void copy_atags(const struct tag *tags)
{
const struct tag *t;
struct tag *copy;
if (!tags)
return;
/* Calculate necessary size for tags we want to copy */
for_each_tag(t, tags) {
if (skip_atag(t->hdr.tag))
continue;
if (t->hdr.tag == ATAG_SERIAL)
parse_serial(&t->u.serialnr);
fw_atags_size += t->hdr.size * sizeof(u32);
}
if (!fw_atags_size)
return; /* No tags to copy */
copy = malloc(fw_atags_size);
if (!copy)
return;
fw_atags_copy = copy;
/* Copy tags */
for_each_tag(t, tags) {
if (skip_atag(t->hdr.tag))
continue;
memcpy(copy, t, t->hdr.size * sizeof(u32));
copy = tag_next(copy);
}
}
int misc_init_r(void)
{
copy_atags(fw_atags_get());
return 0;
}
void setup_board_tags(struct tag **in_params)
{
if (!fw_atags_copy)
return;
/*
* fw_atags_copy contains only full "struct tag" (plus data)
* so copying it bytewise here should be fine.
*/
memcpy(*in_params, fw_atags_copy, fw_atags_size);
*(u8 **)in_params += fw_atags_size;
}

View File

@ -31,11 +31,15 @@ int __weak show_board_info(void)
if (IS_ENABLED(CONFIG_SYSINFO)) {
/* This might provide more detail */
ret = uclass_first_device_err(UCLASS_SYSINFO, &dev);
if (!ret)
ret = sysinfo_get_str(dev,
ret = sysinfo_get(&dev);
if (!ret) {
ret = sysinfo_detect(dev);
if (!ret) {
ret = sysinfo_get_str(dev,
SYSINFO_ID_BOARD_MODEL,
sizeof(str), str);
}
}
}
/* Fail back to the main 'model' if available */

View File

@ -1,7 +1,7 @@
CONFIG_ARM=y
CONFIG_ARCH_U8500=y
CONFIG_SYS_TEXT_BASE=0x100000
CONFIG_NR_DRAM_BANKS=1
CONFIG_NR_DRAM_BANKS=2
CONFIG_DEFAULT_DEVICE_TREE="ste-ux500-samsung-stemmy"
CONFIG_SYS_CONSOLE_INFO_QUIET=y
CONFIG_HUSH_PARSER=y

View File

@ -13,8 +13,7 @@ CONFIG_FIT=y
CONFIG_FIT_SIGNATURE=y
CONFIG_LEGACY_IMAGE_FORMAT=y
CONFIG_BOOTDELAY=5
CONFIG_USE_BOOTARGS=y
CONFIG_BOOTARGS="console=ttyAMA0 debug user_debug=31 earlycon=pl011,0x7ff80000 loglevel=9 androidboot.hardware=total_compute video=640x480-32@60 androidboot.boot_devices=1c050000.mmci ip=dhcp androidboot.selinux=permissive"
# CONFIG_USE_BOOTARGS is not set
# CONFIG_USE_BOOTCOMMAND is not set
# CONFIG_DISPLAY_CPUINFO is not set
# CONFIG_DISPLAY_BOARDINFO is not set

View File

@ -46,6 +46,7 @@ alias simongoldschmidt Simon Goldschmidt <simon.k.r.goldschmidt@gmail.com>
alias sjg Simon Glass <sjg@chromium.org>
alias smcnutt Scott McNutt <smcnutt@psyent.com>
alias stroese Stefan Roese <sr@denx.de>
alias tienfong Tien Fong Chee <tien.fong.chee@intel.com>
alias trini Tom Rini <trini@konsulko.com>
alias wd Wolfgang Denk <wd@denx.de>
alias priyankajain Priyanka Jain <priyanka.jain@nxp.com>
@ -69,7 +70,7 @@ alias s3c samsung
alias s5pc samsung
alias samsung uboot, prom
alias snapdragon uboot, mateusz
alias socfpga uboot, marex, dinh, simongoldschmidt, leyfoon
alias socfpga uboot, marex, dinh, simongoldschmidt, tienfong
alias sunxi uboot, jagan, apritzel
alias tegra uboot, sjg, Tom Warren <twarren@nvidia.com>, Stephen Warren <swarren@nvidia.com>
alias tegra2 tegra

View File

@ -80,6 +80,8 @@ source "drivers/phy/allwinner/Kconfig"
source "drivers/phy/marvell/Kconfig"
source "drivers/phy/socionext/Kconfig"
source "drivers/pinctrl/Kconfig"
source "drivers/power/Kconfig"

View File

@ -96,6 +96,7 @@ obj-$(CONFIG_PCH) += pch/
obj-y += phy/allwinner/
obj-y += phy/marvell/
obj-y += phy/rockchip/
obj-y += phy/socionext/
obj-y += rtc/
obj-y += scsi/
obj-y += sound/

View File

@ -29,6 +29,7 @@ const struct uniphier_clk_data uniphier_pxs2_sys_clk_data[] = {
UNIPHIER_CLK_GATE_SIMPLE(15, 0x2104, 17), /* usb31 (Pro4, Pro5, PXs2) */
UNIPHIER_CLK_GATE_SIMPLE(16, 0x2104, 19), /* usb30-phy (PXs2) */
UNIPHIER_CLK_GATE_SIMPLE(20, 0x2104, 20), /* usb31-phy (PXs2) */
UNIPHIER_CLK_GATE_SIMPLE(24, 0x2108, 2), /* pcie (Pro5) */
{ /* sentinel */ }
#endif
};
@ -43,6 +44,7 @@ const struct uniphier_clk_data uniphier_ld20_sys_clk_data[] = {
UNIPHIER_CLK_GATE_SIMPLE(14, 0x210c, 14), /* usb30 (LD20) */
UNIPHIER_CLK_GATE_SIMPLE(16, 0x210c, 12), /* usb30-phy0 (LD20) */
UNIPHIER_CLK_GATE_SIMPLE(17, 0x210c, 13), /* usb30-phy1 (LD20) */
UNIPHIER_CLK_GATE_SIMPLE(24, 0x210c, 4), /* pcie */
{ /* sentinel */ }
#endif
};
@ -62,6 +64,7 @@ const struct uniphier_clk_data uniphier_pxs3_sys_clk_data[] = {
UNIPHIER_CLK_GATE_SIMPLE(18, 0x210c, 20), /* usb30-phy2 */
UNIPHIER_CLK_GATE_SIMPLE(20, 0x210c, 17), /* usb31-phy0 */
UNIPHIER_CLK_GATE_SIMPLE(21, 0x210c, 19), /* usb31-phy1 */
UNIPHIER_CLK_GATE_SIMPLE(24, 0x210c, 3), /* pcie */
{ /* sentinel */ }
#endif
};

View File

@ -495,4 +495,12 @@ config NX_GPIO
The GPIOs for a device are defined in the device tree with one node
for each bank.
config NOMADIK_GPIO
bool "Nomadik GPIO driver"
depends on DM_GPIO
help
Support GPIO access on ST-Ericsson Ux500 SoCs. The GPIOs are arranged
into a number of banks each with 32 GPIOs. The GPIOs for a device are
defined in the device tree with one node for each bank.
endmenu

View File

@ -43,7 +43,6 @@ obj-$(CONFIG_MPC8XXX_GPIO) += mpc8xxx_gpio.o
obj-$(CONFIG_MPC83XX_SPISEL_BOOT) += mpc83xx_spisel_boot.o
obj-$(CONFIG_SH_GPIO_PFC) += sh_pfc.o
obj-$(CONFIG_OMAP_GPIO) += omap_gpio.o
obj-$(CONFIG_DB8500_GPIO) += db8500_gpio.o
obj-$(CONFIG_BCM2835_GPIO) += bcm2835_gpio.o
obj-$(CONFIG_XILINX_GPIO) += xilinx_gpio.o
obj-$(CONFIG_ADI_GPIO2) += adi_gpio2.o
@ -68,3 +67,4 @@ obj-$(CONFIG_MT7621_GPIO) += mt7621_gpio.o
obj-$(CONFIG_MSCC_SGPIO) += mscc_sgpio.o
obj-$(CONFIG_NX_GPIO) += nx_gpio.o
obj-$(CONFIG_SIFIVE_GPIO) += sifive-gpio.o
obj-$(CONFIG_NOMADIK_GPIO) += nmk_gpio.o

View File

@ -1,221 +0,0 @@
/*
* Code ported from Nomadik GPIO driver in ST-Ericsson Linux kernel code.
* The purpose is that GPIO config found in kernel should work by simply
* copy-paste it to U-Boot.
*
* Original Linux authors:
* Copyright (C) 2008,2009 STMicroelectronics
* Copyright (C) 2009 Alessandro Rubini <rubini@unipv.it>
* Rewritten based on work by Prafulla WADASKAR <prafulla.wadaskar@st.com>
*
* Ported to U-Boot by:
* Copyright (C) 2010 Joakim Axelsson <joakim.axelsson AT stericsson.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#include <common.h>
#include <asm/io.h>
#include <asm/arch/db8500_gpio.h>
#include <asm/arch/db8500_pincfg.h>
#include <linux/compiler.h>
#define IO_ADDR(x) (void *) (x)
/*
* The GPIO module in the db8500 Systems-on-Chip is an
* AMBA device, managing 32 pins and alternate functions. The logic block
* is currently only used in the db8500.
*/
#define GPIO_TOTAL_PINS 268
#define GPIO_PINS_PER_BLOCK 32
#define GPIO_BLOCKS_COUNT (GPIO_TOTAL_PINS/GPIO_PINS_PER_BLOCK + 1)
#define GPIO_BLOCK(pin) (((pin + GPIO_PINS_PER_BLOCK) >> 5) - 1)
#define GPIO_PIN_WITHIN_BLOCK(pin) ((pin)%(GPIO_PINS_PER_BLOCK))
/* Register in the logic block */
#define DB8500_GPIO_DAT 0x00
#define DB8500_GPIO_DATS 0x04
#define DB8500_GPIO_DATC 0x08
#define DB8500_GPIO_PDIS 0x0c
#define DB8500_GPIO_DIR 0x10
#define DB8500_GPIO_DIRS 0x14
#define DB8500_GPIO_DIRC 0x18
#define DB8500_GPIO_SLPC 0x1c
#define DB8500_GPIO_AFSLA 0x20
#define DB8500_GPIO_AFSLB 0x24
#define DB8500_GPIO_RIMSC 0x40
#define DB8500_GPIO_FIMSC 0x44
#define DB8500_GPIO_IS 0x48
#define DB8500_GPIO_IC 0x4c
#define DB8500_GPIO_RWIMSC 0x50
#define DB8500_GPIO_FWIMSC 0x54
#define DB8500_GPIO_WKS 0x58
static void __iomem *get_gpio_addr(unsigned gpio)
{
/* Our list of GPIO chips */
static void __iomem *gpio_addrs[GPIO_BLOCKS_COUNT] = {
IO_ADDR(CFG_GPIO_0_BASE),
IO_ADDR(CFG_GPIO_1_BASE),
IO_ADDR(CFG_GPIO_2_BASE),
IO_ADDR(CFG_GPIO_3_BASE),
IO_ADDR(CFG_GPIO_4_BASE),
IO_ADDR(CFG_GPIO_5_BASE),
IO_ADDR(CFG_GPIO_6_BASE),
IO_ADDR(CFG_GPIO_7_BASE),
IO_ADDR(CFG_GPIO_8_BASE)
};
return gpio_addrs[GPIO_BLOCK(gpio)];
}
static unsigned get_gpio_offset(unsigned gpio)
{
return GPIO_PIN_WITHIN_BLOCK(gpio);
}
/* Can only be called from config_pin. Don't configure alt-mode directly */
static void gpio_set_mode(unsigned gpio, enum db8500_gpio_alt mode)
{
void __iomem *addr = get_gpio_addr(gpio);
unsigned offset = get_gpio_offset(gpio);
u32 bit = 1 << offset;
u32 afunc, bfunc;
afunc = readl(addr + DB8500_GPIO_AFSLA) & ~bit;
bfunc = readl(addr + DB8500_GPIO_AFSLB) & ~bit;
if (mode & DB8500_GPIO_ALT_A)
afunc |= bit;
if (mode & DB8500_GPIO_ALT_B)
bfunc |= bit;
writel(afunc, addr + DB8500_GPIO_AFSLA);
writel(bfunc, addr + DB8500_GPIO_AFSLB);
}
/**
* db8500_gpio_set_pull() - enable/disable pull up/down on a gpio
* @gpio: pin number
* @pull: one of DB8500_GPIO_PULL_DOWN, DB8500_GPIO_PULL_UP,
* and DB8500_GPIO_PULL_NONE
*
* Enables/disables pull up/down on a specified pin. This only takes effect if
* the pin is configured as an input (either explicitly or by the alternate
* function).
*
* NOTE: If enabling the pull up/down, the caller must ensure that the GPIO is
* configured as an input. Otherwise, due to the way the controller registers
* work, this function will change the value output on the pin.
*/
void db8500_gpio_set_pull(unsigned gpio, enum db8500_gpio_pull pull)
{
void __iomem *addr = get_gpio_addr(gpio);
unsigned offset = get_gpio_offset(gpio);
u32 bit = 1 << offset;
u32 pdis;
pdis = readl(addr + DB8500_GPIO_PDIS);
if (pull == DB8500_GPIO_PULL_NONE)
pdis |= bit;
else
pdis &= ~bit;
writel(pdis, addr + DB8500_GPIO_PDIS);
if (pull == DB8500_GPIO_PULL_UP)
writel(bit, addr + DB8500_GPIO_DATS);
else if (pull == DB8500_GPIO_PULL_DOWN)
writel(bit, addr + DB8500_GPIO_DATC);
}
void db8500_gpio_make_input(unsigned gpio)
{
void __iomem *addr = get_gpio_addr(gpio);
unsigned offset = get_gpio_offset(gpio);
writel(1 << offset, addr + DB8500_GPIO_DIRC);
}
int db8500_gpio_get_input(unsigned gpio)
{
void __iomem *addr = get_gpio_addr(gpio);
unsigned offset = get_gpio_offset(gpio);
u32 bit = 1 << offset;
printf("db8500_gpio_get_input gpio=%u addr=%p offset=%u bit=%#x\n",
gpio, addr, offset, bit);
return (readl(addr + DB8500_GPIO_DAT) & bit) != 0;
}
void db8500_gpio_make_output(unsigned gpio, int val)
{
void __iomem *addr = get_gpio_addr(gpio);
unsigned offset = get_gpio_offset(gpio);
writel(1 << offset, addr + DB8500_GPIO_DIRS);
db8500_gpio_set_output(gpio, val);
}
void db8500_gpio_set_output(unsigned gpio, int val)
{
void __iomem *addr = get_gpio_addr(gpio);
unsigned offset = get_gpio_offset(gpio);
if (val)
writel(1 << offset, addr + DB8500_GPIO_DATS);
else
writel(1 << offset, addr + DB8500_GPIO_DATC);
}
/**
* config_pin - configure a pin's mux attributes
* @cfg: pin configuration
*
* Configures a pin's mode (alternate function or GPIO), its pull up status,
* and its sleep mode based on the specified configuration. The @cfg is
* usually one of the SoC specific macros defined in mach/<soc>-pins.h. These
* are constructed using, and can be further enhanced with, the macros in
* plat/pincfg.h.
*
* If a pin's mode is set to GPIO, it is configured as an input to avoid
* side-effects. The gpio can be manipulated later using standard GPIO API
* calls.
*/
static void config_pin(unsigned long cfg)
{
int pin = PIN_NUM(cfg);
int pull = PIN_PULL(cfg);
int af = PIN_ALT(cfg);
int output = PIN_DIR(cfg);
int val = PIN_VAL(cfg);
if (output)
db8500_gpio_make_output(pin, val);
else {
db8500_gpio_make_input(pin);
db8500_gpio_set_pull(pin, pull);
}
gpio_set_mode(pin, af);
}
/**
* db8500_config_pins - configure several pins at once
* @cfgs: array of pin configurations
* @num: number of elments in the array
*
* Configures several pins using config_pin(). Refer to that function for
* further information.
*/
void db8500_gpio_config_pins(unsigned long *cfgs, size_t num)
{
size_t i;
for (i = 0; i < num; i++)
config_pin(cfgs[i]);
}

125
drivers/gpio/nmk_gpio.c Normal file
View File

@ -0,0 +1,125 @@
// SPDX-License-Identifier: GPL-2.0+
/* Copyright (C) 2019 Stephan Gerhold */
#include <common.h>
#include <dm.h>
#include <asm/gpio.h>
#include <asm/io.h>
struct nmk_gpio_regs {
u32 dat; /* data */
u32 dats; /* data set */
u32 datc; /* data clear */
u32 pdis; /* pull disable */
u32 dir; /* direction */
u32 dirs; /* direction set */
u32 dirc; /* direction clear */
u32 slpm; /* sleep mode */
u32 afsla; /* alternate function select A */
u32 afslb; /* alternate function select B */
u32 lowemi; /* low EMI mode */
};
struct nmk_gpio {
struct nmk_gpio_regs *regs;
};
static int nmk_gpio_get_value(struct udevice *dev, unsigned offset)
{
struct nmk_gpio *priv = dev_get_priv(dev);
return !!(readl(&priv->regs->dat) & BIT(offset));
}
static int nmk_gpio_set_value(struct udevice *dev, unsigned offset, int value)
{
struct nmk_gpio *priv = dev_get_priv(dev);
if (value)
writel(BIT(offset), &priv->regs->dats);
else
writel(BIT(offset), &priv->regs->datc);
return 0;
}
static int nmk_gpio_get_function(struct udevice *dev, unsigned offset)
{
struct nmk_gpio *priv = dev_get_priv(dev);
if (readl(&priv->regs->afsla) & BIT(offset) ||
readl(&priv->regs->afslb) & BIT(offset))
return GPIOF_FUNC;
if (readl(&priv->regs->dir) & BIT(offset))
return GPIOF_OUTPUT;
else
return GPIOF_INPUT;
}
static int nmk_gpio_direction_input(struct udevice *dev, unsigned offset)
{
struct nmk_gpio *priv = dev_get_priv(dev);
writel(BIT(offset), &priv->regs->dirc);
return 0;
}
static int nmk_gpio_direction_output(struct udevice *dev, unsigned offset,
int value)
{
struct nmk_gpio *priv = dev_get_priv(dev);
writel(BIT(offset), &priv->regs->dirs);
return nmk_gpio_set_value(dev, offset, value);
}
static const struct dm_gpio_ops nmk_gpio_ops = {
.get_value = nmk_gpio_get_value,
.set_value = nmk_gpio_set_value,
.get_function = nmk_gpio_get_function,
.direction_input = nmk_gpio_direction_input,
.direction_output = nmk_gpio_direction_output,
};
static int nmk_gpio_probe(struct udevice *dev)
{
struct nmk_gpio *priv = dev_get_priv(dev);
struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev);
char buf[20];
u32 bank;
int ret;
priv->regs = dev_read_addr_ptr(dev);
if (!priv->regs)
return -EINVAL;
ret = dev_read_u32(dev, "gpio-bank", &bank);
if (ret < 0) {
printf("nmk_gpio(%s): Failed to read gpio-bank\n", dev->name);
return ret;
}
sprintf(buf, "nmk%u-gpio", bank);
uc_priv->bank_name = strdup(buf);
if (!uc_priv->bank_name)
return -ENOMEM;
uc_priv->gpio_count = sizeof(priv->regs->dat) * BITS_PER_BYTE;
return 0;
}
static const struct udevice_id nmk_gpio_ids[] = {
{ .compatible = "st,nomadik-gpio" },
{ }
};
U_BOOT_DRIVER(gpio_nmk) = {
.name = "nmk_gpio",
.id = UCLASS_GPIO,
.of_match = nmk_gpio_ids,
.probe = nmk_gpio_probe,
.ops = &nmk_gpio_ops,
.priv_auto = sizeof(struct nmk_gpio),
};

View File

@ -264,6 +264,7 @@ static const struct i2c_eeprom_drv_data atmel24c512_data = {
static const struct udevice_id i2c_eeprom_std_ids[] = {
{ .compatible = "i2c-eeprom", (ulong)&eeprom_data },
{ .compatible = "microchip,24aa02e48", (ulong)&mc24aa02e48_data },
{ .compatible = "atmel,24c01", (ulong)&atmel24c01a_data },
{ .compatible = "atmel,24c01a", (ulong)&atmel24c01a_data },
{ .compatible = "atmel,24c02", (ulong)&atmel24c02_data },
{ .compatible = "atmel,24c04", (ulong)&atmel24c04_data },

View File

@ -340,4 +340,14 @@ config PCI_BRCMSTB
on Broadcom set-top-box (STB) SoCs.
This driver currently supports only BCM2711 SoC and RC mode
of the controller.
config PCIE_UNIPHIER
bool "Socionext UniPhier PCIe driver"
depends on DM_PCI
depends on ARCH_UNIPHIER
select PHY_UNIPHIER_PCIE
help
Say Y here if you want to enable PCIe controller support on
UniPhier SoCs.
endif

View File

@ -56,3 +56,4 @@ obj-$(CONFIG_PCI_BRCMSTB) += pcie_brcmstb.o
obj-$(CONFIG_PCI_OCTEONTX) += pci_octeontx.o
obj-$(CONFIG_PCIE_OCTEON) += pcie_octeon.o
obj-$(CONFIG_PCIE_DW_SIFIVE) += pcie_dw_sifive.o
obj-$(CONFIG_PCIE_UNIPHIER) += pcie_uniphier.o

424
drivers/pci/pcie_uniphier.c Normal file
View File

@ -0,0 +1,424 @@
// SPDX-License-Identifier: GPL-2.0
/*
* pcie_uniphier.c - Socionext UniPhier PCIe driver
* Copyright 2019-2021 Socionext, Inc.
*/
#include <clk.h>
#include <common.h>
#include <dm.h>
#include <dm/device_compat.h>
#include <generic-phy.h>
#include <linux/bitfield.h>
#include <linux/bitops.h>
#include <linux/compat.h>
#include <linux/delay.h>
#include <linux/io.h>
#include <pci.h>
#include <reset.h>
DECLARE_GLOBAL_DATA_PTR;
/* DBI registers */
#define PCIE_LINK_STATUS_REG 0x0080
#define PCIE_LINK_STATUS_WIDTH_MASK GENMASK(25, 20)
#define PCIE_LINK_STATUS_SPEED_MASK GENMASK(19, 16)
#define PCIE_MISC_CONTROL_1_OFF 0x08BC
#define PCIE_DBI_RO_WR_EN BIT(0)
/* DBI iATU registers */
#define PCIE_ATU_VIEWPORT 0x0900
#define PCIE_ATU_REGION_INBOUND BIT(31)
#define PCIE_ATU_REGION_OUTBOUND 0
#define PCIE_ATU_REGION_INDEX_MASK GENMASK(3, 0)
#define PCIE_ATU_CR1 0x0904
#define PCIE_ATU_TYPE_MEM 0
#define PCIE_ATU_TYPE_IO 2
#define PCIE_ATU_TYPE_CFG0 4
#define PCIE_ATU_TYPE_CFG1 5
#define PCIE_ATU_CR2 0x0908
#define PCIE_ATU_ENABLE BIT(31)
#define PCIE_ATU_MATCH_MODE BIT(30)
#define PCIE_ATU_BAR_NUM_MASK GENMASK(10, 8)
#define PCIE_ATU_LOWER_BASE 0x090C
#define PCIE_ATU_UPPER_BASE 0x0910
#define PCIE_ATU_LIMIT 0x0914
#define PCIE_ATU_LOWER_TARGET 0x0918
#define PCIE_ATU_BUS(x) FIELD_PREP(GENMASK(31, 24), x)
#define PCIE_ATU_DEV(x) FIELD_PREP(GENMASK(23, 19), x)
#define PCIE_ATU_FUNC(x) FIELD_PREP(GENMASK(18, 16), x)
#define PCIE_ATU_UPPER_TARGET 0x091C
/* Link Glue registers */
#define PCL_PINCTRL0 0x002c
#define PCL_PERST_PLDN_REGEN BIT(12)
#define PCL_PERST_NOE_REGEN BIT(11)
#define PCL_PERST_OUT_REGEN BIT(8)
#define PCL_PERST_PLDN_REGVAL BIT(4)
#define PCL_PERST_NOE_REGVAL BIT(3)
#define PCL_PERST_OUT_REGVAL BIT(0)
#define PCL_MODE 0x8000
#define PCL_MODE_REGEN BIT(8)
#define PCL_MODE_REGVAL BIT(0)
#define PCL_APP_READY_CTRL 0x8008
#define PCL_APP_LTSSM_ENABLE BIT(0)
#define PCL_APP_PM0 0x8078
#define PCL_SYS_AUX_PWR_DET BIT(8)
#define PCL_STATUS_LINK 0x8140
#define PCL_RDLH_LINK_UP BIT(1)
#define PCL_XMLH_LINK_UP BIT(0)
#define LINK_UP_TIMEOUT_MS 100
struct uniphier_pcie_priv {
void *base;
void *dbi_base;
void *cfg_base;
fdt_size_t cfg_size;
struct fdt_resource link_res;
struct fdt_resource dbi_res;
struct fdt_resource cfg_res;
struct clk clk;
struct reset_ctl rst;
struct phy phy;
struct pci_region io;
struct pci_region mem;
};
static int pcie_dw_get_link_speed(struct uniphier_pcie_priv *priv)
{
u32 val = readl(priv->dbi_base + PCIE_LINK_STATUS_REG);
return FIELD_GET(PCIE_LINK_STATUS_SPEED_MASK, val);
}
static int pcie_dw_get_link_width(struct uniphier_pcie_priv *priv)
{
u32 val = readl(priv->dbi_base + PCIE_LINK_STATUS_REG);
return FIELD_GET(PCIE_LINK_STATUS_WIDTH_MASK, val);
}
static void pcie_dw_prog_outbound_atu(struct uniphier_pcie_priv *priv,
int index, int type, u64 cpu_addr,
u64 pci_addr, u32 size)
{
writel(PCIE_ATU_REGION_OUTBOUND
| FIELD_PREP(PCIE_ATU_REGION_INDEX_MASK, index),
priv->dbi_base + PCIE_ATU_VIEWPORT);
writel(lower_32_bits(cpu_addr),
priv->dbi_base + PCIE_ATU_LOWER_BASE);
writel(upper_32_bits(cpu_addr),
priv->dbi_base + PCIE_ATU_UPPER_BASE);
writel(lower_32_bits(cpu_addr + size - 1),
priv->dbi_base + PCIE_ATU_LIMIT);
writel(lower_32_bits(pci_addr),
priv->dbi_base + PCIE_ATU_LOWER_TARGET);
writel(upper_32_bits(pci_addr),
priv->dbi_base + PCIE_ATU_UPPER_TARGET);
writel(type, priv->dbi_base + PCIE_ATU_CR1);
writel(PCIE_ATU_ENABLE, priv->dbi_base + PCIE_ATU_CR2);
}
static int uniphier_pcie_addr_valid(pci_dev_t bdf, int first_busno)
{
/* accept only device {0,1} on first bus */
if ((PCI_BUS(bdf) != first_busno) || (PCI_DEV(bdf) > 1))
return -EINVAL;
return 0;
}
static int uniphier_pcie_conf_address(const struct udevice *dev, pci_dev_t bdf,
uint offset, void **paddr)
{
struct uniphier_pcie_priv *priv = dev_get_priv(dev);
u32 busdev;
int seq = dev_seq(dev);
int ret;
ret = uniphier_pcie_addr_valid(bdf, seq);
if (ret)
return ret;
if ((PCI_BUS(bdf) == seq) && !PCI_DEV(bdf)) {
*paddr = (void *)(priv->dbi_base + offset);
return 0;
}
busdev = PCIE_ATU_BUS(PCI_BUS(bdf) - seq)
| PCIE_ATU_DEV(PCI_DEV(bdf))
| PCIE_ATU_FUNC(PCI_FUNC(bdf));
pcie_dw_prog_outbound_atu(priv, 0,
PCIE_ATU_TYPE_CFG0, (u64)priv->cfg_base,
busdev, priv->cfg_size);
*paddr = (void *)(priv->cfg_base + offset);
return 0;
}
static int uniphier_pcie_read_config(const struct udevice *dev, pci_dev_t bdf,
uint offset, ulong *valp,
enum pci_size_t size)
{
return pci_generic_mmap_read_config(dev, uniphier_pcie_conf_address,
bdf, offset, valp, size);
}
static int uniphier_pcie_write_config(struct udevice *dev, pci_dev_t bdf,
uint offset, ulong val,
enum pci_size_t size)
{
return pci_generic_mmap_write_config(dev, uniphier_pcie_conf_address,
bdf, offset, val, size);
}
static void uniphier_pcie_ltssm_enable(struct uniphier_pcie_priv *priv,
bool enable)
{
u32 val;
val = readl(priv->base + PCL_APP_READY_CTRL);
if (enable)
val |= PCL_APP_LTSSM_ENABLE;
else
val &= ~PCL_APP_LTSSM_ENABLE;
writel(val, priv->base + PCL_APP_READY_CTRL);
}
static int uniphier_pcie_link_up(struct uniphier_pcie_priv *priv)
{
u32 val, mask;
val = readl(priv->base + PCL_STATUS_LINK);
mask = PCL_RDLH_LINK_UP | PCL_XMLH_LINK_UP;
return (val & mask) == mask;
}
static int uniphier_pcie_wait_link(struct uniphier_pcie_priv *priv)
{
unsigned long timeout;
timeout = get_timer(0) + LINK_UP_TIMEOUT_MS;
while (get_timer(0) < timeout) {
if (uniphier_pcie_link_up(priv))
return 0;
}
return -ETIMEDOUT;
}
static int uniphier_pcie_establish_link(struct uniphier_pcie_priv *priv)
{
if (uniphier_pcie_link_up(priv))
return 0;
uniphier_pcie_ltssm_enable(priv, true);
return uniphier_pcie_wait_link(priv);
}
static void uniphier_pcie_init_rc(struct uniphier_pcie_priv *priv)
{
u32 val;
/* set RC mode */
val = readl(priv->base + PCL_MODE);
val |= PCL_MODE_REGEN;
val &= ~PCL_MODE_REGVAL;
writel(val, priv->base + PCL_MODE);
/* use auxiliary power detection */
val = readl(priv->base + PCL_APP_PM0);
val |= PCL_SYS_AUX_PWR_DET;
writel(val, priv->base + PCL_APP_PM0);
/* assert PERST# */
val = readl(priv->base + PCL_PINCTRL0);
val &= ~(PCL_PERST_NOE_REGVAL | PCL_PERST_OUT_REGVAL
| PCL_PERST_PLDN_REGVAL);
val |= PCL_PERST_NOE_REGEN | PCL_PERST_OUT_REGEN
| PCL_PERST_PLDN_REGEN;
writel(val, priv->base + PCL_PINCTRL0);
uniphier_pcie_ltssm_enable(priv, false);
mdelay(100);
/* deassert PERST# */
val = readl(priv->base + PCL_PINCTRL0);
val |= PCL_PERST_OUT_REGVAL | PCL_PERST_OUT_REGEN;
writel(val, priv->base + PCL_PINCTRL0);
}
static void uniphier_pcie_setup_rc(struct uniphier_pcie_priv *priv,
struct pci_controller *hose)
{
/* Store the IO and MEM windows settings for future use by the ATU */
priv->io.phys_start = hose->regions[0].phys_start; /* IO base */
priv->io.bus_start = hose->regions[0].bus_start; /* IO_bus_addr */
priv->io.size = hose->regions[0].size; /* IO size */
priv->mem.phys_start = hose->regions[1].phys_start; /* MEM base */
priv->mem.bus_start = hose->regions[1].bus_start; /* MEM_bus_addr */
priv->mem.size = hose->regions[1].size; /* MEM size */
/* outbound: IO */
pcie_dw_prog_outbound_atu(priv, 0,
PCIE_ATU_TYPE_IO, priv->io.phys_start,
priv->io.bus_start, priv->io.size);
/* outbound: MEM */
pcie_dw_prog_outbound_atu(priv, 1,
PCIE_ATU_TYPE_MEM, priv->mem.phys_start,
priv->mem.bus_start, priv->mem.size);
}
static int uniphier_pcie_probe(struct udevice *dev)
{
struct uniphier_pcie_priv *priv = dev_get_priv(dev);
struct udevice *ctlr = pci_get_controller(dev);
struct pci_controller *hose = dev_get_uclass_priv(ctlr);
int ret;
priv->base = map_physmem(priv->link_res.start,
fdt_resource_size(&priv->link_res),
MAP_NOCACHE);
priv->dbi_base = map_physmem(priv->dbi_res.start,
fdt_resource_size(&priv->dbi_res),
MAP_NOCACHE);
priv->cfg_size = fdt_resource_size(&priv->cfg_res);
priv->cfg_base = map_physmem(priv->cfg_res.start,
priv->cfg_size, MAP_NOCACHE);
ret = clk_enable(&priv->clk);
if (ret) {
dev_err(dev, "Failed to enable clk: %d\n", ret);
return ret;
}
ret = reset_deassert(&priv->rst);
if (ret) {
dev_err(dev, "Failed to deassert reset: %d\n", ret);
goto out_clk_release;
}
ret = generic_phy_init(&priv->phy);
if (ret) {
dev_err(dev, "Failed to initialize phy: %d\n", ret);
goto out_reset_release;
}
ret = generic_phy_power_on(&priv->phy);
if (ret) {
dev_err(dev, "Failed to power on phy: %d\n", ret);
goto out_phy_exit;
}
uniphier_pcie_init_rc(priv);
/* set DBI to read only */
writel(0, priv->dbi_base + PCIE_MISC_CONTROL_1_OFF);
uniphier_pcie_setup_rc(priv, hose);
if (uniphier_pcie_establish_link(priv)) {
printf("PCIE-%d: Link down\n", dev_seq(dev));
} else {
printf("PCIE-%d: Link up (Gen%d-x%d, Bus%d)\n",
dev_seq(dev), pcie_dw_get_link_speed(priv),
pcie_dw_get_link_width(priv), hose->first_busno);
}
return 0;
out_phy_exit:
generic_phy_exit(&priv->phy);
out_reset_release:
reset_release_all(&priv->rst, 1);
out_clk_release:
clk_release_all(&priv->clk, 1);
return ret;
}
static int uniphier_pcie_of_to_plat(struct udevice *dev)
{
struct uniphier_pcie_priv *priv = dev_get_priv(dev);
const void *fdt = gd->fdt_blob;
int node = dev_of_offset(dev);
int ret;
ret = fdt_get_named_resource(fdt, node, "reg", "reg-names",
"link", &priv->link_res);
if (ret) {
dev_err(dev, "Failed to get link regs: %d\n", ret);
return ret;
}
ret = fdt_get_named_resource(fdt, node, "reg", "reg-names",
"dbi", &priv->dbi_res);
if (ret) {
dev_err(dev, "Failed to get dbi regs: %d\n", ret);
return ret;
}
ret = fdt_get_named_resource(fdt, node, "reg", "reg-names",
"config", &priv->cfg_res);
if (ret) {
dev_err(dev, "Failed to get config regs: %d\n", ret);
return ret;
}
ret = clk_get_by_index(dev, 0, &priv->clk);
if (ret) {
dev_err(dev, "Failed to get clocks property: %d\n", ret);
return ret;
}
ret = reset_get_by_index(dev, 0, &priv->rst);
if (ret) {
dev_err(dev, "Failed to get resets property: %d\n", ret);
return ret;
}
ret = generic_phy_get_by_index(dev, 0, &priv->phy);
if (ret) {
dev_err(dev, "Failed to get phy property: %d\n", ret);
return ret;
}
return 0;
}
static const struct dm_pci_ops uniphier_pcie_ops = {
.read_config = uniphier_pcie_read_config,
.write_config = uniphier_pcie_write_config,
};
static const struct udevice_id uniphier_pcie_ids[] = {
{ .compatible = "socionext,uniphier-pcie", },
{ /* Sentinel */ }
};
U_BOOT_DRIVER(pcie_uniphier) = {
.name = "uniphier-pcie",
.id = UCLASS_PCI,
.of_match = uniphier_pcie_ids,
.probe = uniphier_pcie_probe,
.ops = &uniphier_pcie_ops,
.of_to_plat = uniphier_pcie_of_to_plat,
.priv_auto = sizeof(struct uniphier_pcie_priv),
};

View File

@ -64,6 +64,12 @@ config MIPI_DPHY_HELPERS
help
Provides a number of helpers a core functions for MIPI D-PHY drivers.
config AB8500_USB_PHY
bool "AB8500 USB PHY Driver"
depends on PHY && PMIC_AB8500
help
Support for the USB OTG PHY in ST-Ericsson AB8500.
config BCM6318_USBH_PHY
bool "BCM6318 USBH PHY support"
depends on PHY && ARCH_BMIPS

View File

@ -6,6 +6,7 @@
obj-$(CONFIG_$(SPL_)PHY) += phy-uclass.o
obj-$(CONFIG_$(SPL_)NOP_PHY) += nop-phy.o
obj-$(CONFIG_MIPI_DPHY_HELPERS) += phy-core-mipi-dphy.o
obj-$(CONFIG_AB8500_USB_PHY) += phy-ab8500-usb.o
obj-$(CONFIG_BCM6318_USBH_PHY) += bcm6318-usbh-phy.o
obj-$(CONFIG_BCM6348_USBH_PHY) += bcm6348-usbh-phy.o
obj-$(CONFIG_BCM6358_USBH_PHY) += bcm6358-usbh-phy.o

View File

@ -0,0 +1,52 @@
// SPDX-License-Identifier: GPL-2.0+
/* Copyright (C) 2019 Stephan Gerhold */
#include <common.h>
#include <dm.h>
#include <generic-phy.h>
#include <linux/bitops.h>
#include <power/pmic.h>
#include <power/ab8500.h>
#define AB8500_USB_PHY_CTRL_REG AB8500_USB(0x8A)
#define AB8500_BIT_PHY_CTRL_HOST_EN BIT(0)
#define AB8500_BIT_PHY_CTRL_DEVICE_EN BIT(1)
#define AB8500_USB_PHY_CTRL_MASK (AB8500_BIT_PHY_CTRL_HOST_EN |\
AB8500_BIT_PHY_CTRL_DEVICE_EN)
static int ab8500_usb_phy_power_on(struct phy *phy)
{
struct udevice *dev = phy->dev;
uint set = AB8500_BIT_PHY_CTRL_DEVICE_EN;
if (CONFIG_IS_ENABLED(USB_MUSB_HOST))
set = AB8500_BIT_PHY_CTRL_HOST_EN;
return pmic_clrsetbits(dev->parent, AB8500_USB_PHY_CTRL_REG,
AB8500_USB_PHY_CTRL_MASK, set);
}
static int ab8500_usb_phy_power_off(struct phy *phy)
{
struct udevice *dev = phy->dev;
return pmic_clrsetbits(dev->parent, AB8500_USB_PHY_CTRL_REG,
AB8500_USB_PHY_CTRL_MASK, 0);
}
struct phy_ops ab8500_usb_phy_ops = {
.power_on = ab8500_usb_phy_power_on,
.power_off = ab8500_usb_phy_power_off,
};
static const struct udevice_id ab8500_usb_phy_ids[] = {
{ .compatible = "stericsson,ab8500-usb" },
{ }
};
U_BOOT_DRIVER(ab8500_usb_phy) = {
.name = "ab8500_usb_phy",
.id = UCLASS_PHY,
.of_match = ab8500_usb_phy_ids,
.ops = &ab8500_usb_phy_ops,
};

View File

@ -0,0 +1,12 @@
# SPDX-License-Identifier: GPL-2.0-only
#
# PHY drivers for Socionext platforms.
#
config PHY_UNIPHIER_PCIE
bool "UniPhier PCIe PHY driver"
depends on PHY && ARCH_UNIPHIER
imply REGMAP
help
Enable this to support PHY implemented in PCIe controller
on UniPhier SoCs.

View File

@ -0,0 +1,6 @@
# SPDX-License-Identifier: GPL-2.0
#
# Makefile for the phy drivers.
#
obj-$(CONFIG_PHY_UNIPHIER_PCIE) += phy-uniphier-pcie.o

View File

@ -0,0 +1,59 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* phy_uniphier_pcie.c - Socionext UniPhier PCIe PHY driver
* Copyright 2019-2021 Socionext, Inc.
*/
#include <common.h>
#include <dm.h>
#include <generic-phy.h>
#include <linux/bitops.h>
#include <linux/compat.h>
#include <regmap.h>
#include <syscon.h>
/* SG */
#define SG_USBPCIESEL 0x590
#define SG_USBPCIESEL_PCIE BIT(0)
struct uniphier_pciephy_priv {
int dummy;
};
static int uniphier_pciephy_init(struct phy *phy)
{
return 0;
}
static int uniphier_pciephy_probe(struct udevice *dev)
{
struct regmap *regmap;
regmap = syscon_regmap_lookup_by_phandle(dev,
"socionext,syscon");
if (!IS_ERR(regmap))
regmap_update_bits(regmap, SG_USBPCIESEL,
SG_USBPCIESEL_PCIE, SG_USBPCIESEL_PCIE);
return 0;
}
static struct phy_ops uniphier_pciephy_ops = {
.init = uniphier_pciephy_init,
};
static const struct udevice_id uniphier_pciephy_ids[] = {
{ .compatible = "socionext,uniphier-pro5-pcie-phy" },
{ .compatible = "socionext,uniphier-ld20-pcie-phy" },
{ .compatible = "socionext,uniphier-pxs3-pcie-phy" },
{ }
};
U_BOOT_DRIVER(uniphier_pcie_phy) = {
.name = "uniphier-pcie-phy",
.id = UCLASS_PHY,
.of_match = uniphier_pciephy_ids,
.ops = &uniphier_pciephy_ops,
.probe = uniphier_pciephy_probe,
.priv_auto = sizeof(struct uniphier_pciephy_priv),
};

View File

@ -31,6 +31,16 @@ config SPL_PMIC_CHILDREN
to call your regulator code (e.g. see rk8xx.c for direct functions
for use in SPL).
config PMIC_AB8500
bool "Enable driver for ST-Ericsson AB8500 PMIC via PRCMU"
depends on DM_PMIC
select REGMAP
select SYSCON
help
Enable support for the ST-Ericsson AB8500 (Analog Baseband) PMIC.
It connects with the ST-Ericsson DB8500 SoC via an I2C bus managed by
the power/reset/clock management unit (PRCMU) firmware.
config PMIC_ACT8846
bool "Enable support for the active-semi 8846 PMIC"
depends on DM_PMIC && DM_I2C

View File

@ -15,6 +15,7 @@ obj-$(CONFIG_$(SPL_)DM_PMIC_PFUZE100) += pfuze100.o
obj-$(CONFIG_$(SPL_)DM_PMIC_PCA9450) += pca9450.o
obj-$(CONFIG_PMIC_S2MPS11) += s2mps11.o
obj-$(CONFIG_DM_PMIC_SANDBOX) += sandbox.o i2c_pmic_emul.o
obj-$(CONFIG_PMIC_AB8500) += ab8500.o
obj-$(CONFIG_PMIC_ACT8846) += act8846.o
obj-$(CONFIG_PMIC_AS3722) += as3722.o as3722_gpio.o
obj-$(CONFIG_PMIC_MAX8997) += max8997.o

268
drivers/power/pmic/ab8500.c Normal file
View File

@ -0,0 +1,268 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* Copyright (C) 2019 Stephan Gerhold
*
* Adapted from old U-Boot and Linux kernel implementation:
* Copyright (C) STMicroelectronics 2009
* Copyright (C) ST-Ericsson SA 2010
*/
#include <common.h>
#include <dm.h>
#include <regmap.h>
#include <syscon.h>
#include <linux/bitops.h>
#include <linux/err.h>
#include <power/ab8500.h>
#include <power/pmic.h>
/* CPU mailbox registers */
#define PRCM_MBOX_CPU_VAL 0x0fc
#define PRCM_MBOX_CPU_SET 0x100
#define PRCM_MBOX_CPU_CLR 0x104
#define PRCM_ARM_IT1_CLR 0x48C
#define PRCM_ARM_IT1_VAL 0x494
#define PRCM_TCDM_RANGE 2
#define PRCM_REQ_MB5 0xE44
#define PRCM_ACK_MB5 0xDF4
#define _PRCM_MBOX_HEADER 0xFE8
#define PRCM_MBOX_HEADER_REQ_MB5 (_PRCM_MBOX_HEADER + 0x5)
#define PRCMU_I2C_MBOX_BIT BIT(5)
/* Mailbox 5 Requests */
#define PRCM_REQ_MB5_I2C_SLAVE_OP (PRCM_REQ_MB5 + 0x0)
#define PRCM_REQ_MB5_I2C_HW_BITS (PRCM_REQ_MB5 + 0x1)
#define PRCM_REQ_MB5_I2C_REG (PRCM_REQ_MB5 + 0x2)
#define PRCM_REQ_MB5_I2C_VAL (PRCM_REQ_MB5 + 0x3)
#define PRCMU_I2C(bank) (((bank) << 1) | BIT(6))
#define PRCMU_I2C_WRITE 0
#define PRCMU_I2C_READ 1
#define PRCMU_I2C_STOP_EN BIT(3)
/* Mailbox 5 ACKs */
#define PRCM_ACK_MB5_I2C_STATUS (PRCM_ACK_MB5 + 0x1)
#define PRCM_ACK_MB5_I2C_VAL (PRCM_ACK_MB5 + 0x3)
#define PRCMU_I2C_WR_OK 0x1
#define PRCMU_I2C_RD_OK 0x2
/* AB8500 version registers */
#define AB8500_MISC_REV_REG AB8500_MISC(0x80)
#define AB8500_MISC_IC_NAME_REG AB8500_MISC(0x82)
struct ab8500_priv {
struct ab8500 ab8500;
struct regmap *regmap;
};
static inline int prcmu_tcdm_readb(struct regmap *map, uint offset, u8 *valp)
{
return regmap_raw_read_range(map, PRCM_TCDM_RANGE, offset,
valp, sizeof(*valp));
}
static inline int prcmu_tcdm_writeb(struct regmap *map, uint offset, u8 val)
{
return regmap_raw_write_range(map, PRCM_TCDM_RANGE, offset,
&val, sizeof(val));
}
static int prcmu_wait_i2c_mbx_ready(struct ab8500_priv *priv)
{
uint val;
int ret;
ret = regmap_read(priv->regmap, PRCM_ARM_IT1_VAL, &val);
if (ret)
return ret;
if (val & PRCMU_I2C_MBOX_BIT) {
printf("ab8500: warning: PRCMU i2c mailbox was not acked\n");
/* clear mailbox 5 ack irq */
ret = regmap_write(priv->regmap, PRCM_ARM_IT1_CLR,
PRCMU_I2C_MBOX_BIT);
if (ret)
return ret;
}
/* wait for on-going transaction, use 1s timeout */
return regmap_read_poll_timeout(priv->regmap, PRCM_MBOX_CPU_VAL, val,
!(val & PRCMU_I2C_MBOX_BIT), 0, 1000);
}
static int prcmu_wait_i2c_mbx_done(struct ab8500_priv *priv)
{
uint val;
int ret;
/* set interrupt to XP70 */
ret = regmap_write(priv->regmap, PRCM_MBOX_CPU_SET, PRCMU_I2C_MBOX_BIT);
if (ret)
return ret;
/* wait for mailbox 5 (i2c) ack, use 1s timeout */
return regmap_read_poll_timeout(priv->regmap, PRCM_ARM_IT1_VAL, val,
(val & PRCMU_I2C_MBOX_BIT), 0, 1000);
}
static int ab8500_transfer(struct udevice *dev, uint bank_reg, u8 *val,
u8 op, u8 expected_status)
{
struct ab8500_priv *priv = dev_get_priv(dev);
u8 reg = bank_reg & 0xff;
u8 bank = bank_reg >> 8;
u8 status;
int ret;
ret = prcmu_wait_i2c_mbx_ready(priv);
if (ret)
return ret;
ret = prcmu_tcdm_writeb(priv->regmap, PRCM_MBOX_HEADER_REQ_MB5, 0);
if (ret)
return ret;
ret = prcmu_tcdm_writeb(priv->regmap, PRCM_REQ_MB5_I2C_SLAVE_OP,
PRCMU_I2C(bank) | op);
if (ret)
return ret;
ret = prcmu_tcdm_writeb(priv->regmap, PRCM_REQ_MB5_I2C_HW_BITS,
PRCMU_I2C_STOP_EN);
if (ret)
return ret;
ret = prcmu_tcdm_writeb(priv->regmap, PRCM_REQ_MB5_I2C_REG, reg);
if (ret)
return ret;
ret = prcmu_tcdm_writeb(priv->regmap, PRCM_REQ_MB5_I2C_VAL, *val);
if (ret)
return ret;
ret = prcmu_wait_i2c_mbx_done(priv);
if (ret) {
printf("%s: mailbox request timed out\n", __func__);
return ret;
}
/* read transfer result */
ret = prcmu_tcdm_readb(priv->regmap, PRCM_ACK_MB5_I2C_STATUS, &status);
if (ret)
return ret;
ret = prcmu_tcdm_readb(priv->regmap, PRCM_ACK_MB5_I2C_VAL, val);
if (ret)
return ret;
/*
* Clear mailbox 5 ack irq. Note that the transfer is already complete
* here so checking for errors does not make sense. Clearing the irq
* will be retried in prcmu_wait_i2c_mbx_ready() on the next transfer.
*/
regmap_write(priv->regmap, PRCM_ARM_IT1_CLR, PRCMU_I2C_MBOX_BIT);
if (status != expected_status) {
/*
* AB8500 does not have the AB8500_MISC_IC_NAME_REG register,
* but we need to try reading it to detect AB8505.
* In case of an error, assume that we have AB8500.
*/
if (op == PRCMU_I2C_READ && bank_reg == AB8500_MISC_IC_NAME_REG) {
*val = AB8500_VERSION_AB8500;
return 0;
}
printf("%s: return status %d\n", __func__, status);
return -EIO;
}
return 0;
}
static int ab8500_reg_count(struct udevice *dev)
{
return AB8500_NUM_REGISTERS;
}
static int ab8500_read(struct udevice *dev, uint reg, uint8_t *buf, int len)
{
int ret;
if (len != 1)
return -EINVAL;
*buf = 0;
ret = ab8500_transfer(dev, reg, buf, PRCMU_I2C_READ, PRCMU_I2C_RD_OK);
if (ret) {
printf("%s failed: %d\n", __func__, ret);
return ret;
}
return 0;
}
static int ab8500_write(struct udevice *dev, uint reg, const uint8_t *buf, int len)
{
int ret;
u8 val;
if (len != 1)
return -EINVAL;
val = *buf;
ret = ab8500_transfer(dev, reg, &val, PRCMU_I2C_WRITE, PRCMU_I2C_WR_OK);
if (ret) {
printf("%s failed: %d\n", __func__, ret);
return ret;
}
return 0;
}
static struct dm_pmic_ops ab8500_ops = {
.reg_count = ab8500_reg_count,
.read = ab8500_read,
.write = ab8500_write,
};
static int ab8500_probe(struct udevice *dev)
{
struct ab8500_priv *priv = dev_get_priv(dev);
int ret;
/* get regmap from the PRCMU parent device (syscon in U-Boot) */
priv->regmap = syscon_get_regmap(dev->parent);
if (IS_ERR(priv->regmap))
return PTR_ERR(priv->regmap);
ret = pmic_reg_read(dev, AB8500_MISC_IC_NAME_REG);
if (ret < 0) {
printf("ab8500: failed to read chip version: %d\n", ret);
return ret;
}
priv->ab8500.version = ret;
ret = pmic_reg_read(dev, AB8500_MISC_REV_REG);
if (ret < 0) {
printf("ab8500: failed to read chip id: %d\n", ret);
return ret;
}
priv->ab8500.chip_id = ret;
debug("ab8500: version: %#x, chip id: %#x\n",
priv->ab8500.version, priv->ab8500.chip_id);
return 0;
}
static const struct udevice_id ab8500_ids[] = {
{ .compatible = "stericsson,ab8500" },
{ }
};
U_BOOT_DRIVER(pmic_ab8500) = {
.name = "pmic_ab8500",
.id = UCLASS_PMIC,
.of_match = ab8500_ids,
.bind = dm_scan_fdt_dev,
.probe = ab8500_probe,
.ops = &ab8500_ops,
.priv_auto = sizeof(struct ab8500_priv),
};

View File

@ -50,6 +50,7 @@ static const struct uniphier_reset_data uniphier_pro4_sys_reset_data[] = {
UNIPHIER_RESETX(12, 0x2000, 6), /* GIO */
UNIPHIER_RESETX(14, 0x2000, 17), /* USB30 */
UNIPHIER_RESETX(15, 0x2004, 17), /* USB31 */
UNIPHIER_RESETX(24, 0x2008, 2), /* PCIE */
UNIPHIER_RESET_END,
};
@ -79,6 +80,7 @@ static const struct uniphier_reset_data uniphier_ld20_sys_reset_data[] = {
UNIPHIER_RESETX(17, 0x200c, 13), /* USB30-PHY1 */
UNIPHIER_RESETX(18, 0x200c, 14), /* USB30-PHY2 */
UNIPHIER_RESETX(19, 0x200c, 15), /* USB30-PHY3 */
UNIPHIER_RESETX(24, 0x200c, 4), /* PCIE */
UNIPHIER_RESET_END,
};
@ -95,6 +97,7 @@ static const struct uniphier_reset_data uniphier_pxs3_sys_reset_data[] = {
UNIPHIER_RESETX(18, 0x200c, 20), /* USB30-PHY2 */
UNIPHIER_RESETX(20, 0x200c, 17), /* USB31-PHY0 */
UNIPHIER_RESETX(21, 0x200c, 19), /* USB31-PHY1 */
UNIPHIER_RESETX(24, 0x200c, 3), /* PCIE */
UNIPHIER_RESET_END,
};

View File

@ -67,14 +67,11 @@ static int nomadik_mtu_probe(struct udevice *dev)
struct timer_dev_priv *uc_priv = dev_get_uclass_priv(dev);
struct nomadik_mtu_priv *priv = dev_get_priv(dev);
struct nomadik_mtu_regs *mtu;
fdt_addr_t addr;
u32 prescale;
addr = dev_read_addr(dev);
if (addr == FDT_ADDR_T_NONE)
mtu = dev_read_addr_ptr(dev);
if (!mtu)
return -EINVAL;
mtu = (struct nomadik_mtu_regs *)addr;
priv->timer = mtu->timers; /* Use first timer */
if (!uc_priv->clock_rate)

View File

@ -72,6 +72,15 @@ config USB_MUSB_SUNXI
Say y here to enable support for the sunxi OTG / DRC USB controller
used on almost all sunxi boards.
config USB_MUSB_UX500
bool "Enable ST-Ericsson Ux500 USB controller"
depends on DM_USB && DM_USB_GADGET && ARCH_U8500
default y
help
Say y to enable support for the MUSB OTG USB controller used in
ST-Ericsson Ux500. The driver supports either gadget or host mode
based on the selection of CONFIG_USB_MUSB_HOST.
config USB_MUSB_DISABLE_BULK_COMBINE_SPLIT
bool "Disable MUSB bulk split/combine"
default y
@ -85,7 +94,7 @@ endif
config USB_MUSB_PIO_ONLY
bool "Disable DMA (always use PIO)"
default y if USB_MUSB_AM35X || USB_MUSB_PIC32 || USB_MUSB_OMAP2PLUS || USB_MUSB_DSPS || USB_MUSB_SUNXI || USB_MUSB_MT85XX
default y if USB_MUSB_AM35X || USB_MUSB_PIC32 || USB_MUSB_OMAP2PLUS || USB_MUSB_DSPS || USB_MUSB_SUNXI || USB_MUSB_MT85XX || USB_MUSB_UX500
help
All data is copied between memory and FIFO by the CPU.
DMA controllers are ignored.

View File

@ -13,6 +13,7 @@ obj-$(CONFIG_USB_MUSB_OMAP2PLUS) += omap2430.o
obj-$(CONFIG_USB_MUSB_PIC32) += pic32.o
obj-$(CONFIG_USB_MUSB_SUNXI) += sunxi.o
obj-$(CONFIG_USB_MUSB_TI) += ti-musb.o
obj-$(CONFIG_USB_MUSB_UX500) += ux500.o
ccflags-y := $(call cc-option,-Wno-unused-variable) \
$(call cc-option,-Wno-unused-but-set-variable) \

View File

@ -1526,7 +1526,7 @@ static int __devinit musb_core_init(u16 musb_type, struct musb *musb)
/*-------------------------------------------------------------------------*/
#if defined(CONFIG_SOC_OMAP2430) || defined(CONFIG_SOC_OMAP3430) || \
defined(CONFIG_ARCH_OMAP4)
defined(CONFIG_ARCH_OMAP4) || defined(CONFIG_ARCH_U8500)
static irqreturn_t generic_interrupt(int irq, void *__hci)
{

View File

@ -0,0 +1,179 @@
// SPDX-License-Identifier: GPL-2.0+
/* Copyright (C) 2019 Stephan Gerhold */
#include <common.h>
#include <dm.h>
#include <generic-phy.h>
#include <dm/device_compat.h>
#include "musb_uboot.h"
static struct musb_hdrc_config ux500_musb_hdrc_config = {
.multipoint = true,
.dyn_fifo = true,
.num_eps = 16,
.ram_bits = 16,
};
struct ux500_glue {
struct musb_host_data mdata;
struct device dev;
struct phy phy;
bool enabled;
};
#define to_ux500_glue(d) container_of(d, struct ux500_glue, dev)
static int ux500_musb_enable(struct musb *musb)
{
struct ux500_glue *glue = to_ux500_glue(musb->controller);
int ret;
if (glue->enabled)
return 0;
ret = generic_phy_power_on(&glue->phy);
if (ret) {
printf("%s: failed to power on USB PHY\n", __func__);
return ret;
}
glue->enabled = true;
return 0;
}
static void ux500_musb_disable(struct musb *musb)
{
struct ux500_glue *glue = to_ux500_glue(musb->controller);
int ret;
if (!glue->enabled)
return;
ret = generic_phy_power_off(&glue->phy);
if (ret) {
printf("%s: failed to power off USB PHY\n", __func__);
return;
}
glue->enabled = false;
}
static int ux500_musb_init(struct musb *musb)
{
struct ux500_glue *glue = to_ux500_glue(musb->controller);
int ret;
ret = generic_phy_init(&glue->phy);
if (ret) {
printf("%s: failed to init USB PHY\n", __func__);
return ret;
}
return 0;
}
static int ux500_musb_exit(struct musb *musb)
{
struct ux500_glue *glue = to_ux500_glue(musb->controller);
int ret;
ret = generic_phy_exit(&glue->phy);
if (ret) {
printf("%s: failed to exit USB PHY\n", __func__);
return ret;
}
return 0;
}
static const struct musb_platform_ops ux500_musb_ops = {
.init = ux500_musb_init,
.exit = ux500_musb_exit,
.enable = ux500_musb_enable,
.disable = ux500_musb_disable,
};
int dm_usb_gadget_handle_interrupts(struct udevice *dev)
{
struct ux500_glue *glue = dev_get_priv(dev);
glue->mdata.host->isr(0, glue->mdata.host);
return 0;
}
static int ux500_musb_probe(struct udevice *dev)
{
#ifdef CONFIG_USB_MUSB_HOST
struct usb_bus_priv *priv = dev_get_uclass_priv(dev);
#endif
struct ux500_glue *glue = dev_get_priv(dev);
struct musb_host_data *host = &glue->mdata;
struct musb_hdrc_platform_data pdata;
void *base = dev_read_addr_ptr(dev);
int ret;
if (!base)
return -EINVAL;
ret = generic_phy_get_by_name(dev, "usb", &glue->phy);
if (ret) {
dev_err(dev, "failed to get USB PHY: %d\n", ret);
return ret;
}
memset(&pdata, 0, sizeof(pdata));
pdata.platform_ops = &ux500_musb_ops;
pdata.config = &ux500_musb_hdrc_config;
#ifdef CONFIG_USB_MUSB_HOST
priv->desc_before_addr = true;
pdata.mode = MUSB_HOST;
host->host = musb_init_controller(&pdata, &glue->dev, base);
if (!host->host)
return -EIO;
return musb_lowlevel_init(host);
#else
pdata.mode = MUSB_PERIPHERAL;
host->host = musb_init_controller(&pdata, &glue->dev, base);
if (!host->host)
return -EIO;
return usb_add_gadget_udc(&glue->dev, &host->host->g);
#endif
}
static int ux500_musb_remove(struct udevice *dev)
{
struct ux500_glue *glue = dev_get_priv(dev);
struct musb_host_data *host = &glue->mdata;
usb_del_gadget_udc(&host->host->g);
musb_stop(host->host);
free(host->host);
host->host = NULL;
return 0;
}
static const struct udevice_id ux500_musb_ids[] = {
{ .compatible = "stericsson,db8500-musb" },
{ }
};
U_BOOT_DRIVER(ux500_musb) = {
.name = "ux500-musb",
#ifdef CONFIG_USB_MUSB_HOST
.id = UCLASS_USB,
#else
.id = UCLASS_USB_GADGET_GENERIC,
#endif
.of_match = ux500_musb_ids,
.probe = ux500_musb_probe,
.remove = ux500_musb_remove,
#ifdef CONFIG_USB_MUSB_HOST
.ops = &musb_usb_ops,
#endif
.plat_auto = sizeof(struct usb_plat),
.priv_auto = sizeof(struct ux500_glue),
};

View File

@ -7,23 +7,23 @@
#include <linux/sizes.h>
#define CONFIG_SKIP_LOWLEVEL_INIT /* Loaded by another bootloader */
#define CONFIG_SYS_MALLOC_LEN SZ_2M
/*
* The "stemmy" U-Boot port is designed to be chainloaded by the Samsung
* bootloader on devices based on ST-Ericsson Ux500. Therefore, we skip most
* low-level initialization and rely on configuration provided by the Samsung
* bootloader. New images are loaded at the same address for compatibility.
*/
#define CONFIG_SKIP_LOWLEVEL_INIT
#define CONFIG_SYS_INIT_SP_ADDR CONFIG_SYS_TEXT_BASE
#define CONFIG_SYS_LOAD_ADDR CONFIG_SYS_TEXT_BASE
/* Physical Memory Map */
#define PHYS_SDRAM_1 0x00000000 /* DDR-SDRAM Bank #1 */
#define CONFIG_SYS_SDRAM_BASE PHYS_SDRAM_1
#define CONFIG_SYS_SDRAM_SIZE SZ_1G
#define CONFIG_SYS_INIT_RAM_SIZE 0x00100000
#define CONFIG_SYS_GBL_DATA_OFFSET (CONFIG_SYS_SDRAM_BASE + \
CONFIG_SYS_INIT_RAM_SIZE - \
GENERATED_GBL_DATA_SIZE)
#define CONFIG_SYS_INIT_SP_ADDR CONFIG_SYS_GBL_DATA_OFFSET
#define CONFIG_SYS_MALLOC_LEN SZ_2M
/* FIXME: This should be loaded from device tree... */
#define CONFIG_SYS_L2_PL310
#define CONFIG_SYS_PL310_BASE 0xa0412000
#define CONFIG_SYS_LOAD_ADDR 0x00100000
/* Generate initrd atag for downstream kernel (others are copied in stemmy.c) */
#define CONFIG_INITRD_TAG
#endif

View File

@ -210,4 +210,6 @@
#define CONFIG_SPL_PAD_TO 0x20000
#define CONFIG_SYS_PCI_64BIT
#endif /* __CONFIG_UNIPHIER_H__ */

125
include/power/ab8500.h Normal file
View File

@ -0,0 +1,125 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Based on include/linux/mfd/abx500/ab8500.h from Linux
* Copyright (C) ST-Ericsson SA 2010
* Author: Srinidhi Kasagar <srinidhi.kasagar@stericsson.com>
*/
#ifndef _PMIC_AB8500_H_
#define _PMIC_AB8500_H_
/*
* AB IC versions
*
* AB8500_VERSION_AB8500 should be 0xFF but will never be read as need a
* non-supported multi-byte I2C access via PRCMU. Set to 0x00 to ease the
* print of version string.
*/
enum ab8500_version {
AB8500_VERSION_AB8500 = 0x0,
AB8500_VERSION_AB8505 = 0x1,
AB8500_VERSION_AB9540 = 0x2,
AB8500_VERSION_AB8540 = 0x4,
AB8500_VERSION_UNDEFINED,
};
/* AB8500 CIDs*/
#define AB8500_CUTEARLY 0x00
#define AB8500_CUT1P0 0x10
#define AB8500_CUT1P1 0x11
#define AB8500_CUT1P2 0x12 /* Only valid for AB8540 */
#define AB8500_CUT2P0 0x20
#define AB8500_CUT3P0 0x30
#define AB8500_CUT3P3 0x33
/*
* AB8500 bank addresses
*/
#define AB8500_BANK(bank, reg) (((bank) << 8) | (reg))
#define AB8500_M_FSM_RANK(reg) AB8500_BANK(0x0, reg)
#define AB8500_SYS_CTRL1_BLOCK(reg) AB8500_BANK(0x1, reg)
#define AB8500_SYS_CTRL2_BLOCK(reg) AB8500_BANK(0x2, reg)
#define AB8500_REGU_CTRL1(reg) AB8500_BANK(0x3, reg)
#define AB8500_REGU_CTRL2(reg) AB8500_BANK(0x4, reg)
#define AB8500_USB(reg) AB8500_BANK(0x5, reg)
#define AB8500_TVOUT(reg) AB8500_BANK(0x6, reg)
#define AB8500_DBI(reg) AB8500_BANK(0x7, reg)
#define AB8500_ECI_AV_ACC(reg) AB8500_BANK(0x8, reg)
#define AB8500_RESERVED(reg) AB8500_BANK(0x9, reg)
#define AB8500_GPADC(reg) AB8500_BANK(0xA, reg)
#define AB8500_CHARGER(reg) AB8500_BANK(0xB, reg)
#define AB8500_GAS_GAUGE(reg) AB8500_BANK(0xC, reg)
#define AB8500_AUDIO(reg) AB8500_BANK(0xD, reg)
#define AB8500_INTERRUPT(reg) AB8500_BANK(0xE, reg)
#define AB8500_RTC(reg) AB8500_BANK(0xF, reg)
#define AB8500_GPIO(reg) AB8500_BANK(0x10, reg)
#define AB8500_MISC(reg) AB8500_BANK(0x10, reg)
#define AB8500_DEVELOPMENT(reg) AB8500_BANK(0x11, reg)
#define AB8500_DEBUG(reg) AB8500_BANK(0x12, reg)
#define AB8500_PROD_TEST(reg) AB8500_BANK(0x13, reg)
#define AB8500_STE_TEST(reg) AB8500_BANK(0x14, reg)
#define AB8500_OTP_EMUL(reg) AB8500_BANK(0x15, reg)
#define AB8500_NUM_BANKS 0x16
#define AB8500_NUM_REGISTERS AB8500_BANK(AB8500_NUM_BANKS, 0)
struct ab8500 {
enum ab8500_version version;
u8 chip_id;
};
static inline int is_ab8500(struct ab8500 *ab)
{
return ab->version == AB8500_VERSION_AB8500;
}
static inline int is_ab8505(struct ab8500 *ab)
{
return ab->version == AB8500_VERSION_AB8505;
}
/* exclude also ab8505, ab9540... */
static inline int is_ab8500_1p0_or_earlier(struct ab8500 *ab)
{
return (is_ab8500(ab) && (ab->chip_id <= AB8500_CUT1P0));
}
/* exclude also ab8505, ab9540... */
static inline int is_ab8500_1p1_or_earlier(struct ab8500 *ab)
{
return (is_ab8500(ab) && (ab->chip_id <= AB8500_CUT1P1));
}
/* exclude also ab8505, ab9540... */
static inline int is_ab8500_2p0_or_earlier(struct ab8500 *ab)
{
return (is_ab8500(ab) && (ab->chip_id <= AB8500_CUT2P0));
}
static inline int is_ab8500_3p3_or_earlier(struct ab8500 *ab)
{
return (is_ab8500(ab) && (ab->chip_id <= AB8500_CUT3P3));
}
/* exclude also ab8505, ab9540... */
static inline int is_ab8500_2p0(struct ab8500 *ab)
{
return (is_ab8500(ab) && (ab->chip_id == AB8500_CUT2P0));
}
static inline int is_ab8505_1p0_or_earlier(struct ab8500 *ab)
{
return (is_ab8505(ab) && (ab->chip_id <= AB8500_CUT1P0));
}
static inline int is_ab8505_2p0(struct ab8500 *ab)
{
return (is_ab8505(ab) && (ab->chip_id == AB8500_CUT2P0));
}
static inline int is_ab8505_2p0_earlier(struct ab8500 *ab)
{
return (is_ab8505(ab) && (ab->chip_id < AB8500_CUT2P0));
}
#endif