diff options
Diffstat (limited to 'board/samsung')
| -rw-r--r-- | board/samsung/e850-96/Makefile | 2 | ||||
| -rw-r--r-- | board/samsung/e850-96/acpm.c | 169 | ||||
| -rw-r--r-- | board/samsung/e850-96/acpm.h | 27 | ||||
| -rw-r--r-- | board/samsung/e850-96/e850-96.c | 96 | ||||
| -rw-r--r-- | board/samsung/e850-96/e850-96.env | 2 | ||||
| -rw-r--r-- | board/samsung/e850-96/fw.c | 45 | ||||
| -rw-r--r-- | board/samsung/e850-96/fw.h | 4 | ||||
| -rw-r--r-- | board/samsung/e850-96/pmic.c | 144 | ||||
| -rw-r--r-- | board/samsung/e850-96/pmic.h | 14 | ||||
| -rw-r--r-- | board/samsung/n1/Kconfig | 13 | ||||
| -rw-r--r-- | board/samsung/n1/MAINTAINERS | 9 | ||||
| -rw-r--r-- | board/samsung/n1/bose.config | 6 | ||||
| -rw-r--r-- | board/samsung/n1/n1.env | 16 | ||||
| -rw-r--r-- | board/samsung/odroid/odroid.c | 15 | 
14 files changed, 514 insertions, 48 deletions
| diff --git a/board/samsung/e850-96/Makefile b/board/samsung/e850-96/Makefile index 71d46ea3d2b..76b8d47994e 100644 --- a/board/samsung/e850-96/Makefile +++ b/board/samsung/e850-96/Makefile @@ -3,4 +3,4 @@  # Copyright (C) 2024, Linaro Limited  # Sam Protsenko <semen.protsenko@linaro.org> -obj-y	:= e850-96.o fw.o +obj-y := e850-96.o fw.o acpm.o pmic.o diff --git a/board/samsung/e850-96/acpm.c b/board/samsung/e850-96/acpm.c new file mode 100644 index 00000000000..1cc5c6d0e4a --- /dev/null +++ b/board/samsung/e850-96/acpm.c @@ -0,0 +1,169 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (c) 2025 Linaro Ltd. + * Author: Sam Protsenko <semen.protsenko@linaro.org> + * + * ACPM (Active Clock and Power Management) is an IPC protocol for communicating + * with APM (Active Power Management) core. The message exchange between AP + * (Application Processor) and APM is happening by using shared memory in SRAM + * (iRAM) and generating interrupts using Mailbox block. By using this IPC + * interface it's possible to offload power management tasks to APM core, which + * acts as a supervisor for CPU. One of the main tasks of APM is controlling + * PMIC chip over I3C bus. So in order to access PMIC chip registers it's + * recommended to do so by sending corresponding commands to APM via ACPM IPC + * protocol. The IPC interaction sequence looks like this: + * + *     AP (CPU) <-> ACPM IPC (Mailbox + SRAM) <-> APM <-> I3C <-> PMIC + * + * This file contains functions for accessing I3C bus via APM block using + * ACPM IPC. + */ + +#include <linux/iopoll.h> +#include <linux/time.h> +#include <asm/io.h> +#include "acpm.h" + +/* Mailbox registers */ +#define MBOX_INTGR0			0x8	/* Interrupt Generation */ +#define MBOX_INTCR1			0x20	/* Interrupt Clear */ +#define MBOX_INTSR1			0x28	/* Interrupt Status */ +#define MBOX_INTGR_OFFSET		16 +#define MBOX_TIMEOUT			(1 * USEC_PER_SEC) + +/* APM shared memory registers */ +#define SHMEM_SR0			0x0 +#define SHMEM_SR1			0x4 +#define SHMEM_SR2			0x8 +#define SHMEM_SR3			0xc + +/* IPC functions */ +#define IPC_FUNC_READ			0x0 +#define IPC_FUNC_WRITE			0x1 +/* Command 0 shifts and masks */ +#define IPC_REG_SHIFT			0 +#define IPC_REG_MASK			0xff +#define IPC_TYPE_SHIFT			8 +#define IPC_TYPE_MASK			0xf +#define IPC_CHANNEL_SHIFT		12 +#define IPC_CHANNEL_MASK		0xf +/* Command 1 shifts and masks */ +#define IPC_FUNC_SHIFT			0 +#define IPC_FUNC_MASK			0xff +#define IPC_WRITE_VAL_SHIFT		8 +#define IPC_WRITE_VAL_MASK		0xff +/* Command 3 shifts and masks */ +#define IPC_DEST_SHIFT			8 +#define IPC_DEST_MASK			0xff +#define IPC_RETURN_SHIFT		24 +#define IPC_RETURN_MASK			0xff + +/** + * acpm_ipc_send_data_async() - Send data to I3C block over ACPM IPC + * @acpm: ACPM data + * @cmd0: Command 0 value to send + * @cmd1: Command 1 value to send + */ +static void acpm_ipc_send_data_async(struct acpm *acpm, u32 cmd0, u32 cmd1) +{ +	u32 irq_bit = 1 << acpm->ipc_ch; +	u32 intgr = irq_bit << MBOX_INTGR_OFFSET; + +	/* Write data to the shared memory */ +	writel(cmd0, acpm->sram_base + SHMEM_SR0); +	writel(cmd1, acpm->sram_base + SHMEM_SR1); +	dsb(); + +	/* Generate interrupt for I3C block */ +	writel(intgr, acpm->mbox_base + MBOX_INTGR0); +} + +/** + * acpm_ipc_wait_resp() - Read response data from I3C block over ACPM IPC + * @acpm: ACPM data + * @cmd2: Will contain read value for command 2 + * @cmd3: Will contain read value for command 3 + * + * Return: 0 on success or negative value on error. + */ +static int acpm_ipc_wait_resp(struct acpm *acpm, u32 *cmd2, u32 *cmd3) +{ +	u32 irq_bit = 1 << acpm->ipc_ch; +	u32 reg; +	int ret; + +	/* Wait for the interrupt from I3C block */ +	ret = readl_poll_timeout(acpm->mbox_base + MBOX_INTSR1, reg, +				 reg & irq_bit, MBOX_TIMEOUT); +	if (ret < 0) +		return ret; + +	/* Clear the interrupt */ +	writel(irq_bit, acpm->mbox_base + MBOX_INTCR1); + +	/* Read data from the shared memory */ +	*cmd2 = readl(acpm->sram_base + SHMEM_SR2); +	*cmd3 = readl(acpm->sram_base + SHMEM_SR3); + +	return 0; +} + +/** + * acpm_i3c_read() - Read an I3C register of some I3C slave device + * @acpm: ACPM data + * @ch: I3C channel (bus) number (0-15) + * @addr: I3C address of slave device (0-15) + * @reg: Address of I3C register in the slave device to read from + * @val: Will contain the read value + * + * Return: 0 on success or non-zero code on error (may be positive). + */ +int acpm_i3c_read(struct acpm *acpm, u8 ch, u8 addr, u8 reg, u8 *val) +{ +	u32 cmd[4] = { 0 }; +	u8 ret; + +	cmd[0] = (ch & IPC_CHANNEL_MASK) << IPC_CHANNEL_SHIFT | +		 (addr & IPC_TYPE_MASK) << IPC_TYPE_SHIFT | +		 (reg & IPC_REG_MASK) << IPC_REG_SHIFT; +	cmd[1] = IPC_FUNC_READ << IPC_FUNC_SHIFT; + +	acpm_ipc_send_data_async(acpm, cmd[0], cmd[1]); +	ret = acpm_ipc_wait_resp(acpm, &cmd[2], &cmd[3]); +	if (ret) +		return ret; + +	*val = (cmd[3] >> IPC_DEST_SHIFT) & IPC_DEST_MASK; +	ret = (cmd[3] >> IPC_RETURN_SHIFT) & IPC_RETURN_MASK; +	return ret; +} + +/** + * acpm_i3c_write() - Write an I3C register of some I3C slave device + * @acpm: ACPM data + * @ch: I3C channel (bus) number (0-15) + * @addr: I3C address of slave device (0-15) + * @reg: Address of I3C register in the slave device to write into + * @val: Value to write + * + * Return: 0 on success or non-zero code on error (may be positive). + */ +int acpm_i3c_write(struct acpm *acpm, u8 ch, u8 addr, u8 reg, u8 val) +{ +	u32 cmd[4] = { 0 }; +	u8 ret; + +	cmd[0] = (ch & IPC_CHANNEL_MASK) << IPC_CHANNEL_SHIFT | +		 (addr & IPC_TYPE_MASK) << IPC_TYPE_SHIFT | +		 (reg & IPC_REG_MASK) << IPC_REG_SHIFT; +	cmd[1] = IPC_FUNC_WRITE << IPC_FUNC_SHIFT | +		 (val & IPC_WRITE_VAL_MASK) << IPC_WRITE_VAL_SHIFT; + +	acpm_ipc_send_data_async(acpm, cmd[0], cmd[1]); +	ret = acpm_ipc_wait_resp(acpm, &cmd[2], &cmd[3]); +	if (ret) +		return ret; + +	ret = (cmd[3] >> IPC_RETURN_SHIFT) & IPC_RETURN_MASK; +	return ret; +} diff --git a/board/samsung/e850-96/acpm.h b/board/samsung/e850-96/acpm.h new file mode 100644 index 00000000000..9373969209f --- /dev/null +++ b/board/samsung/e850-96/acpm.h @@ -0,0 +1,27 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * Copyright (c) 2025 Linaro Ltd. + * Sam Protsenko <semen.protsenko@linaro.org> + */ + +#ifndef __E850_96_ACPM_H +#define __E850_96_ACPM_H + +#include <linux/types.h> + +/** + * struct acpm - Data for I3C communication over ACPM IPC protocol + * @mbox_base: Base address of APM mailbox block + * @sram_base: Base address of shared memory used for APM messages + * @ipc_ch: Mailbox channel number used for communication with I3C block (0-15) + */ +struct acpm { +	void __iomem *mbox_base; +	void __iomem *sram_base; +	u8 ipc_ch; +}; + +int acpm_i3c_read(struct acpm *acpm, u8 ch, u8 addr, u8 reg, u8 *val); +int acpm_i3c_write(struct acpm *acpm, u8 ch, u8 addr, u8 reg, u8 val); + +#endif /* __E850_96_ACPM_H */ diff --git a/board/samsung/e850-96/e850-96.c b/board/samsung/e850-96/e850-96.c index 4e034b9bd3b..3df241edde2 100644 --- a/board/samsung/e850-96/e850-96.c +++ b/board/samsung/e850-96/e850-96.c @@ -8,13 +8,28 @@  #include <env.h>  #include <init.h>  #include <mapmem.h> +#include <net.h> +#include <usb.h>  #include <asm/io.h>  #include "fw.h" +#include "pmic.h"  /* OTP Controller base address and register offsets */ -#define EXYNOS850_OTP_BASE	0x10000000 -#define OTP_CHIPID0		0x4 -#define OTP_CHIPID1		0x8 +#define EXYNOS850_OTP_BASE		0x10000000 +#define OTP_CHIPID0			0x4 +#define OTP_CHIPID1			0x8 + +/* ACPM and PMIC definitions */ +#define EXYNOS850_MBOX_APM2AP_BASE	0x11900000 +#define EXYNOS850_APM_SRAM_BASE		0x02039000	/* in iRAM */ +#define EXYNOS850_APM_SHMEM_OFFSET	0x3200 +#define EXYNOS850_IPC_AP_I3C		10 + +/* LDFW firmware definitions */ +#define LDFW_NWD_ADDR			0x88000000 +#define EMMC_IFNAME			"mmc" +#define EMMC_DEV_NUM			0 +#define EMMC_ESP_PART			1  struct efi_fw_image fw_images[] = {  	{ @@ -55,6 +70,13 @@ struct efi_capsule_update_info update_info = {  	.images = fw_images,  }; +static struct acpm acpm = { +	.mbox_base	= (void __iomem *)EXYNOS850_MBOX_APM2AP_BASE, +	.sram_base	= (void __iomem *)(EXYNOS850_APM_SRAM_BASE + +					   EXYNOS850_APM_SHMEM_OFFSET), +	.ipc_ch		= EXYNOS850_IPC_AP_I3C, +}; +  int dram_init(void)  {  	return fdtdec_setup_mem_size_base(); @@ -92,24 +114,74 @@ static void setup_serial(void)  	env_set("serial#", serial_str);  } -int board_init(void) +static void setup_ethaddr(void)  { -	return 0; +	u64 serial_num; +	u32 mac_hi, mac_lo; +	u8 mac_addr[6]; + +	if (env_get("ethaddr")) +		return; + +	serial_num = get_chip_id(); +	mac_lo = (u32)serial_num;		/* OTP_CHIPID0 */ +	mac_hi = (u32)(serial_num >> 32UL);	/* OTP_CHIPID1 */ +	mac_addr[0] = (mac_hi >> 8) & 0xff; +	mac_addr[1] = mac_hi & 0xff; +	mac_addr[2] = (mac_lo >> 24) & 0xff; +	mac_addr[3] = (mac_lo >> 16) & 0xff; +	mac_addr[4] = (mac_lo >> 8) & 0xff; +	mac_addr[5] = mac_lo & 0xff; +	mac_addr[0] &= ~0x1; /* make sure it's not a multicast address */ +	if (is_valid_ethaddr(mac_addr)) +		eth_env_set_enetaddr("ethaddr", mac_addr);  } -int board_late_init(void) +/* + * Call this in board_late_init() to avoid probing block devices before + * efi_init_early(). + */ +void load_firmware(void)  { +	const char *ifname; +	ulong dev, part;  	int err; +	ifname = env_get("bootdev"); +	if (!ifname) +		ifname = EMMC_IFNAME; +	dev = env_get_ulong("bootdevnum", 10, EMMC_DEV_NUM); +	part = env_get_ulong("bootdevpart", 10, EMMC_ESP_PART); + +	if (!strcmp(ifname, "usb")) { +		printf("Starting USB (bootdev=usb)...\n"); +		err = usb_init(); +		if (err) +			return; +	} + +	printf("Loading LDFW firmware (from %s %ld)...\n", ifname, dev); +	err = load_ldfw(ifname, dev, part, LDFW_NWD_ADDR); +	if (err) +		printf("ERROR: LDFW loading failed (%d)\n", err); +} + +int board_late_init(void) +{  	setup_serial(); +	setup_ethaddr(); +	load_firmware(); + +	return 0; +} + +int power_init_board(void) +{ +	int err; -	/* -	 * Do this in board_late_init() to make sure MMC is not probed before -	 * efi_init_early(). -	 */ -	err = load_ldfw(); +	err = pmic_init(&acpm);  	if (err) -		printf("ERROR: LDFW loading failed (%d)\n", err); +		printf("ERROR: Failed to configure PMIC (%d)\n", err);  	return 0;  } diff --git a/board/samsung/e850-96/e850-96.env b/board/samsung/e850-96/e850-96.env index aed7a71046d..992318b0ab2 100644 --- a/board/samsung/e850-96/e850-96.env +++ b/board/samsung/e850-96/e850-96.env @@ -5,7 +5,7 @@ fdt_addr_r=0x8c000000  scriptaddr=0x8c100000  pxefile_addr_r=0x8c200000  ramdisk_addr_r=0x8c300000 -fdtfile=CONFIG_DEFAULT_FDT_FILE +fdtfile=exynos/exynos850-e850-96.dtb  dfu_alt_info=  	rawemmc raw 0 0x747c000 mmcpart 1; diff --git a/board/samsung/e850-96/fw.c b/board/samsung/e850-96/fw.c index 8f64e759b43..64235c01a25 100644 --- a/board/samsung/e850-96/fw.c +++ b/board/samsung/e850-96/fw.c @@ -11,13 +11,9 @@  #include <linux/arm-smccc.h>  #include "fw.h" -#define EMMC_IFACE		"mmc" -#define EMMC_DEV_NUM		0  #define LDFW_RAW_PART		"ldfw" -#define LDFW_FAT_PART		"esp"  #define LDFW_FAT_PATH		"/EFI/firmware/ldfw.bin" -#define LDFW_NWD_ADDR		0x88000000  #define LDFW_MAGIC		0x10adab1e  #define SMC_CMD_LOAD_LDFW	-0x500  #define SDM_HW_RESET_STATUS	0x1230 @@ -39,19 +35,23 @@ struct ldfw_header {  };  /* Load LDFW binary as a file from FAT partition */ -static int read_fw_from_fat(const char *part_name, const char *path, void *buf) +static int read_fw_from_fat(const char *ifname, int dev, int part, +			    const char *path, void *buf)  { -	char dev_part_str[8]; +	struct blk_desc *blk_desc;  	loff_t len_read;  	int err; -	snprintf(dev_part_str, sizeof(dev_part_str), "%d#%s", EMMC_DEV_NUM, -		 LDFW_FAT_PART); +	blk_desc = blk_get_dev(ifname, dev); +	if (!blk_desc) { +		debug("%s: Can't get block device\n", __func__); +		return -ENODEV; +	} -	err = fs_set_blk_dev(EMMC_IFACE, dev_part_str, FS_TYPE_FAT); +	err = fs_set_blk_dev_with_part(blk_desc, part);  	if (err) { -		debug("%s: Can't set block device\n", __func__); -		return -ENODEV; +		debug("%s: Can't set partition\n", __func__); +		return -ENOENT;  	}  	err = fs_read(path, (ulong)buf, 0, 0, &len_read); @@ -64,16 +64,17 @@ static int read_fw_from_fat(const char *part_name, const char *path, void *buf)  }  /* Load LDFW binary from raw partition on block device into RAM buffer */ -static int read_fw_from_raw(const char *part_name, void *buf) +static int read_fw_from_raw(const char *ifname, int dev, const char *part_name, +			    void *buf)  {  	struct blk_desc *blk_desc;  	struct disk_partition part;  	unsigned long cnt;  	int part_num; -	blk_desc = blk_get_dev(EMMC_IFACE, EMMC_DEV_NUM); +	blk_desc = blk_get_dev(ifname, dev);  	if (!blk_desc) { -		debug("%s: Can't get eMMC device\n", __func__); +		debug("%s: Can't get block device\n", __func__);  		return -ENODEV;  	} @@ -92,9 +93,17 @@ static int read_fw_from_raw(const char *part_name, void *buf)  	return 0;  } -int load_ldfw(void) +/** + * load_ldfw - Load the loadable firmware (LDFW) + * @ifname: Interface name of the block device to load the firmware from + * @dev: Device number + * @part: Partition number + * @addr: Temporary memory (Normal World) to use for loading the firmware + * + * Return: 0 on success or a negative value on error. + */ +int load_ldfw(const char *ifname, int dev, int part, phys_addr_t addr)  { -	const phys_addr_t addr = (phys_addr_t)LDFW_NWD_ADDR;  	struct ldfw_header *hdr;  	struct arm_smccc_res res;  	void *buf = (void *)addr; @@ -102,9 +111,9 @@ int load_ldfw(void)  	int err, i;  	/* First try to read LDFW from EFI partition, then from the raw one */ -	err = read_fw_from_fat(LDFW_FAT_PART, LDFW_FAT_PATH, buf); +	err = read_fw_from_fat(ifname, dev, part, LDFW_FAT_PATH, buf);  	if (err) { -		err = read_fw_from_raw(LDFW_RAW_PART, buf); +		err = read_fw_from_raw(ifname, dev, LDFW_RAW_PART, buf);  		if (err)  			return err;  	} diff --git a/board/samsung/e850-96/fw.h b/board/samsung/e850-96/fw.h index 472664e4ed2..73d9615d4a9 100644 --- a/board/samsung/e850-96/fw.h +++ b/board/samsung/e850-96/fw.h @@ -7,6 +7,8 @@  #ifndef __E850_96_FW_H  #define __E850_96_FW_H -int load_ldfw(void); +#include <asm/types.h> + +int load_ldfw(const char *ifname, int dev, int part, phys_addr_t addr);  #endif /* __E850_96_FW_H */ diff --git a/board/samsung/e850-96/pmic.c b/board/samsung/e850-96/pmic.c new file mode 100644 index 00000000000..037fd4844c5 --- /dev/null +++ b/board/samsung/e850-96/pmic.c @@ -0,0 +1,144 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (c) 2025 Linaro Ltd. + * Author: Sam Protsenko <semen.protsenko@linaro.org> + * + * This file contains functions for S2MPU12 PMIC regulators configuration. + * + * Example of voltage calculation for LDO24 and LDO32: + *   - V_min = 1800 mV + *   - V_step = 25 mV + *   - V_wanted = 3300 mV + *   - register value: (V_wanted - V_min) / V_step = 60 = 0x3c + * + * NOTE: 0x3c value might mean different voltage for other LDOs. + */ + +#include <linux/errno.h> +#include <linux/kernel.h> +#include "pmic.h" + +/* PMIC definitions */ +#define S2MPU12_CHANNEL			0	/* I3C bus number of PMIC */ +#define S2MPU12_PM_ADDR			0x1	/* I3C slave addr of PM part */ + +/* PMIC I3C registers */ +#define S2MPU12_PM_LDO1_CTRL		0x2b +#define S2MPU12_PM_LDO_CTRL(n)		(S2MPU12_PM_LDO1_CTRL + (n) - 1) + +/* LDOx_CTRL values */ +#define S2MPU12_LDO_CTRL_OUT_MASK	(0x3 << 6) +#define S2MPU12_LDO_CTRL_OUT_ALWAYS_ON	(0x3 << 6) + +struct pmic_ldo { +	u8 num;	/* LDO number */ +	u8 en;	/* "enable" bits value in LDOx_CTRL register */ +	u8 out;	/* "output voltage" bits value in LDOx_CTRL register */ +}; + +/* List of LDOs to enable only */ +static u8 pmic_ldos_en[] = { +	2,	/* 1.8V/450mA:	multiple lines */ +	11,	/* 3.0V/150mA:	AVDD33_USB20 */ +	23,	/* 2.85V/800mA:	VDD_EMMC_2P85 */ +	27,	/* 3.0V/150mA:	MIPI_SWITCH_3V3 */ +	28,	/* 1.8V/150mA:	HDMI_CONV_1V8 */ +	30,	/* 1.8V/150mA:	NPU_VDD18 */ +}; + +/* List of LDOs to enable and set output voltage */ +static struct pmic_ldo pmic_ldos_en_out[] = { +	{ +		.num	= 24, /* 3.0V/800mA:	VDD_LAN (LAN9514) */ +		.en	= S2MPU12_LDO_CTRL_OUT_ALWAYS_ON, +		.out	= 0x3c, /* means 3.3V for LDO24 */ +	}, { +		.num	= 32, /* 3.3V/300mA:	CAM_VDD (RPi camera module) */ +		.en	= S2MPU12_LDO_CTRL_OUT_ALWAYS_ON, +		.out	= 0x3c, /* means 3.3V for LDO32 */ +	}, +}; + +/* Enable specified LDO */ +static int pmic_ldo_set_en(struct acpm *acpm, u8 ldo) +{ +	const u8 reg = S2MPU12_PM_LDO_CTRL(ldo); +	u8 val; +	int err; + +	err = acpm_i3c_read(acpm, S2MPU12_CHANNEL, S2MPU12_PM_ADDR, reg, &val); +	if (err) +		return err; + +	val &= ~S2MPU12_LDO_CTRL_OUT_MASK; +	val |= S2MPU12_LDO_CTRL_OUT_ALWAYS_ON; + +	return acpm_i3c_write(acpm, S2MPU12_CHANNEL, S2MPU12_PM_ADDR, reg, val); +} + +/* Enable specified LDO and set its voltage to 0xc0 value */ +static int pmic_ldo_set_en_out(struct acpm *acpm, struct pmic_ldo *ldo) +{ +	const u8 reg = S2MPU12_PM_LDO_CTRL(ldo->num); +	const u8 val = ldo->en | ldo->out; + +	return acpm_i3c_write(acpm, S2MPU12_CHANNEL, S2MPU12_PM_ADDR, reg, val); +} + +#ifdef DEBUG +static void pmic_trace_ldo(struct acpm *acpm, u8 ldo) +{ +	const u8 reg = S2MPU12_PM_LDO_CTRL(ldo); +	u8 val; +	int err; + +	err = acpm_i3c_read(acpm, S2MPU12_CHANNEL, S2MPU12_PM_ADDR, reg, &val); +	if (err) +		printf("  S2MPU12_PM_LDO%u_CTRL: Read error!\n", ldo); +	else +		printf("  S2MPU12_PM_LDO%u_CTRL: 0x%x\n", ldo, val); +} + +static void pmic_trace_ldos(struct acpm *acpm) +{ +	size_t i; + +	printf("Tracing LDOs...\n"); +	for (i = 0; i < ARRAY_SIZE(pmic_ldos_en); ++i) +		pmic_trace_ldo(acpm, pmic_ldos_en[i]); +	for (i = 0; i < ARRAY_SIZE(pmic_ldos_en_out); ++i) +		pmic_trace_ldo(acpm, pmic_ldos_en_out[i].num); +} +#endif + +/** + * pmic_init() - Enable power regulators in S2MPU12 PMIC. + * @acpm: Data for I3C communication with PMIC over ACPM protocol + * + * Enable LDOs needed for devices used in the bootloader and kernel. + * + * Return: 0 on success or non-zero code on error. + */ +int pmic_init(struct acpm *acpm) +{ +	size_t i; +	int err; + +	for (i = 0; i < ARRAY_SIZE(pmic_ldos_en); ++i) { +		err = pmic_ldo_set_en(acpm, pmic_ldos_en[i]); +		if (err) +			return -EIO; +	} + +	for (i = 0; i < ARRAY_SIZE(pmic_ldos_en_out); ++i) { +		err = pmic_ldo_set_en_out(acpm, &pmic_ldos_en_out[i]); +		if (err) +			return -EIO; +	} + +#ifdef DEBUG +	pmic_trace_ldos(acpm); +#endif + +	return 0; +} diff --git a/board/samsung/e850-96/pmic.h b/board/samsung/e850-96/pmic.h new file mode 100644 index 00000000000..46624c2ebd4 --- /dev/null +++ b/board/samsung/e850-96/pmic.h @@ -0,0 +1,14 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * Copyright (c) 2025 Linaro Ltd. + * Sam Protsenko <semen.protsenko@linaro.org> + */ + +#ifndef __E850_96_PMIC_H +#define __E850_96_PMIC_H + +#include "acpm.h" + +int pmic_init(struct acpm *acpm); + +#endif /* __E850_96_PMIC_H */ diff --git a/board/samsung/n1/Kconfig b/board/samsung/n1/Kconfig new file mode 100644 index 00000000000..a5e5edda9e2 --- /dev/null +++ b/board/samsung/n1/Kconfig @@ -0,0 +1,13 @@ +if TARGET_SAMSUNG_N1 + +config SYS_BOARD +	default "n1" + +config SYS_VENDOR +	default "samsung" + +config TEGRA_BOARD_STRING +	string "Default Tegra board name" +	default "Samsung N1" + +endif diff --git a/board/samsung/n1/MAINTAINERS b/board/samsung/n1/MAINTAINERS new file mode 100644 index 00000000000..798cb56cd37 --- /dev/null +++ b/board/samsung/n1/MAINTAINERS @@ -0,0 +1,9 @@ +N1 BOARD +M:	Ion Agorria <ion@agorria.com> +M:	Svyatoslav Ryhel <clamor95@gmail.com> +S:	Maintained +F:	arch/arm/dts/tegra20-samsung-bose.dts +F:	arch/arm/dts/tegra20-samsung-n1.dts +F:	board/samsung/n1/ +F:	configs/n1_defconfig +F:	doc/board/samsung/n1.rst diff --git a/board/samsung/n1/bose.config b/board/samsung/n1/bose.config new file mode 100644 index 00000000000..6d6d9d3f2ce --- /dev/null +++ b/board/samsung/n1/bose.config @@ -0,0 +1,6 @@ +CONFIG_DEFAULT_DEVICE_TREE="tegra20-samsung-bose" +CONFIG_SYS_PROMPT="Tegra20 (Bose) # " +# CONFIG_VIDEO_BRIDGE_SAMSUNG_CMC623 is not set +# CONFIG_BACKLIGHT_SAMSUNG_CMC623 is not set +# CONFIG_VIDEO_LCD_SONY_L4F00430T01 is not set +CONFIG_VIDEO_LCD_SAMSUNG_S6E63M0=y diff --git a/board/samsung/n1/n1.env b/board/samsung/n1/n1.env new file mode 100644 index 00000000000..e2b883dbc10 --- /dev/null +++ b/board/samsung/n1/n1.env @@ -0,0 +1,16 @@ +#include <env/nvidia/prod_upd.env> + +button_cmd_0_name=Volume Down +button_cmd_0=bootmenu + +boot_block_size_r=0x80000 +boot_block_size=0x400 +boot_dev=1 + +bootmenu_0=mount internal storage=usb start && ums 0 mmc 0; bootmenu +bootmenu_1=mount external storage=usb start && ums 0 mmc 1; bootmenu +bootmenu_2=fastboot=echo Starting Fastboot protocol ...; fastboot usb 0; bootmenu +bootmenu_3=reboot RCM=enterrcm +bootmenu_4=reboot=reset +bootmenu_5=power off=poweroff +bootmenu_delay=-1 diff --git a/board/samsung/odroid/odroid.c b/board/samsung/odroid/odroid.c index 84d6d919f07..a48b8e94b77 100644 --- a/board/samsung/odroid/odroid.c +++ b/board/samsung/odroid/odroid.c @@ -428,21 +428,6 @@ void exynos_init(void)  	board_gpio_init();  } -int exynos_power_init(void) -{ -	const char *mmc_regulators[] = { -		"VDDQ_EMMC_1.8V", -		"VDDQ_EMMC_2.8V", -		"TFLASH_2.8V", -		NULL, -	}; - -	if (regulator_list_autoset(mmc_regulators, NULL, true)) -		pr_err("Unable to init all mmc regulators\n"); - -	return 0; -} -  #ifdef CONFIG_USB_GADGET  static int s5pc210_phy_control(int on)  { | 
