diff --git a/board/samsung/board-dreamlte.c b/board/samsung/board-dreamlte.c index 5f6ba4a..1db9598 100644 --- a/board/samsung/board-dreamlte.c +++ b/board/samsung/board-dreamlte.c @@ -3,11 +3,20 @@ * Copyright (c) 2022, Ivaylo Ivanov */ #include +#include +#include #include #include +#include +#include +#include -#define DECON_F_BASE 0x12860000 -#define HW_SW_TRIG_CONTROL 0x70 +/* DECON Register MAP */ +#define HW_SW_TRIG_CONTROL 0x70 + +/* MMIO MAP */ +#define DECON_F_BASE 0x12860000 +#define SPEEDY_BASE 0x15b50000 void init_board_funcs(void *board) { @@ -23,6 +32,94 @@ void init_board_funcs(void *board) board_restruct->name = "DREAMLTE"; } +enum s2mps17_ldos { + S2MPS17_LDO2, + S2MPS17_LDO34, + S2MPS17_LDO35, + S2MPS17_END +}; + +struct s2mps17_data { + uint8_t ldo_ctrl_value; + uint32_t ldo_voltage_value; +}; + +/* Slave addr = 0xCC */ +/* S2MPS17 Register MAP */ +#define S2MPS17_PMIC_REG_L2CTRL 0x3e +#define S2MPS17_PMIC_REG_L34CTRL 0x5f +#define S2MPS17_PMIC_REG_L35CTRL 0x60 + +#define S2MPS17_BUCK_MIN1 300000 +#define S2MPS17_BUCK_MIN2 600000 +#define S2MPS17_LDO_MIN1 700000 +#define S2MPS17_LDO_MIN2 400000 +#define S2MPS17_LDO_MIN3 1800000 +#define S2MPS17_LDO_MIN4 300000 + +#define S2MPS17_LDO_STEP1 12500 +#define S2MPS17_LDO_STEP2 25000 + +#define S2MPS17_LDO_VSEL_MASK 0x3f +#define S2MPS17_BUCK_VSEL_MASK 0xff + +#define S2MPS17_ENABLE_MASK (3 << 6) + +#define S2MPS17_LDO2_VOLTAGE 2800000 +#define S2MPS17_LDO34_VOLTAGE 1850000 +#define S2MPS17_LDO35_VOLTAGE 3000000 + +#define _LDO(macro) S2MPS17_LDO##macro +#define _REG(ctrl) S2MPS17_PMIC_REG##ctrl +#define _ldo_ops(num) s2mps17_ldo_ops##num +#define _TIME(macro) S2MPS17_ENABLE_TIME##macro + +static void s2mps17_setup(void) +{ + int ret; + struct speedy_transaction s2mps17; + + /* S2MPS17 configuration */ + s2mps17.base = SPEEDY_BASE; + s2mps17.slave = 1; + + /* + * Define LDO control register values + * Calculation formula: enable mask + (voltage to set - minimal voltage) / step value + */ + const struct s2mps17_data data[] = { + { + S2MPS17_PMIC_REG_L2CTRL, // vqmmc + S2MPS17_ENABLE_MASK + (S2MPS17_LDO2_VOLTAGE - + S2MPS17_LDO_MIN3) / S2MPS17_LDO_STEP2 + }, { + S2MPS17_PMIC_REG_L34CTRL, // tsp_io + S2MPS17_ENABLE_MASK + (S2MPS17_LDO34_VOLTAGE - + S2MPS17_LDO_MIN1) / S2MPS17_LDO_STEP2 + }, { + S2MPS17_PMIC_REG_L35CTRL, // tsp_avdd + S2MPS17_ENABLE_MASK + (S2MPS17_LDO35_VOLTAGE - + S2MPS17_LDO_MIN3) / S2MPS17_LDO_STEP2 + } + }; + + /* Go ahead and enable the LDOs */ + for (int i = 0; i < S2MPS17_END; i++) { + s2mps17.offset = data[i].ldo_ctrl_value; + s2mps17.val = data[i].ldo_voltage_value; + + ret = speedy_write(&s2mps17); + if (ret) + goto handle_err; + } + + return; + + handle_err: + printk(KERN_ERR, "s2mps17: err\n"); + return; +} + // Early initialization int board_init(void) { @@ -34,6 +131,8 @@ int board_init(void) // Late initialization int board_late_init(void) { + s2mps17_setup(); + return 0; } diff --git a/drivers/Makefile b/drivers/Makefile index 6beb20a..8afe40a 100644 --- a/drivers/Makefile +++ b/drivers/Makefile @@ -1,2 +1,3 @@ # the drivers registration framework lib-y += framework.o +lib-y += samsung/exynos-speedy.o diff --git a/drivers/samsung/exynos-speedy.c b/drivers/samsung/exynos-speedy.c new file mode 100644 index 0000000..0fb2152 --- /dev/null +++ b/drivers/samsung/exynos-speedy.c @@ -0,0 +1,196 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (c) 2024, Ivaylo Ivanov + * Copyright (c) 2024 Markuss Broks + */ +#include +#include +#include +#include + +/* SPEEDY Register MAP */ +#define SPEEDY_CTRL 0x000 +#define SPEEDY_FIFO_CTRL 0x004 +#define SPEEDY_CMD 0x008 +#define SPEEDY_INT_ENABLE 0x00c +#define SPEEDY_INT_STATUS 0x010 +#define SPEEDY_FIFO_STATUS 0x030 +#define SPEEDY_TX_DATA 0x034 +#define SPEEDY_RX_DATA 0x038 +#define SPEEDY_PACKET_GAP_TIME 0x044 +#define SPEEDY_TIMEOUT_COUNT 0x048 +#define SPEEDY_FIFO_DEBUG 0x100 +#define SPEEDY_CTRL_STATUS 0x104 + +/* SPEEDY_CTRL Register bits */ +#define SPEEDY_ENABLE (1 << 0) +#define SPEEDY_TIMEOUT_CMD_DISABLE (1 << 1) +#define SPEEDY_TIMEOUT_STANDBY_DISABLE (1 << 2) +#define SPEEDY_TIMEOUT_DATA_DISABLE (1 << 3) +#define SPEEDY_ALWAYS_PULLUP_EN (1 << 7) +#define SPEEDY_DATA_WIDTH_8BIT (0 << 8) +#define SPEEDY_REMOTE_RESET_REQ (1 << 30) +#define SPEEDY_SW_RST (1 << 31) + +/* SPEEDY_FIFO_CTRL Register bits */ +#define SPEEDY_RX_TRIGGER_LEVEL(x) ((x) << 0) +#define SPEEDY_TX_TRIGGER_LEVEL(x) ((x) << 8) +#define SPEEDY_FIFO_DEBUG_INDEX (0 << 24) +#define SPEEDY_FIFO_RESET (1 << 31) + +/* SPEEDY_CMD Register bits */ +#define SPEEDY_BURST_LENGTH(x) ((x) << 0) +#define SPEEDY_BURST_FIXED (0 << 5) +#define SPEEDY_BURST_INCR (1 << 5) +#define SPEEDY_BURST_EXTENSION (2 << 5) +#define SPEEDY_ACCESS_BURST (0 << 19) +#define SPEEDY_ACCESS_RANDOM (1 << 19) +#define SPEEDY_DIRECTION_READ (0 << 20) +#define SPEEDY_DIRECTION_WRITE (1 << 20) + +/* SPEEDY_INT_ENABLE Register bits */ +#define SPEEDY_TRANSFER_DONE_EN (1 << 0) +#define SPEEDY_TIMEOUT_CMD_EN (1 << 1) +#define SPEEDY_TIMEOUT_STANDBY_EN (1 << 2) +#define SPEEDY_TIMEOUT_DATA_EN (1 << 3) +#define SPEEDY_FIFO_RX_ALMOST_FULL_EN (1 << 8) +#define SPEEDY_FIFO_TX_ALMOST_EMPTY_EN (1 << 4) +#define SPEEDY_RX_FIFO_INT_TRAILER_EN (1 << 9) +#define SPEEDY_RX_MODEBIT_ERR_EN (1 << 16) +#define SPEEDY_RX_GLITCH_ERR_EN (1 << 17) +#define SPEEDY_RX_ENDBIT_ERR_EN (1 << 18) +#define SPEEDY_TX_LINE_BUSY_ERR_EN (1 << 20) +#define SPEEDY_TX_STOPBIT_ERR_EN (1 << 21) +#define SPEEDY_REMOTE_RESET_REQ_EN (1 << 31) + +/* SPEEDY_INT_STATUS Register bits */ +#define SPEEDY_TRANSFER_DONE (1 << 0) +#define SPEEDY_TIMEOUT_CMD (1 << 1) +#define SPEEDY_TIMEOUT_STANDBY (1 << 2) +#define SPEEDY_TIMEOUT_DATA (1 << 3) +#define SPEEDY_FIFO_TX_ALMOST_EMPTY (1 << 4) +#define SPEEDY_FIFO_RX_ALMOST_FULL (1 << 8) +#define SPEEDY_RX_FIFO_INT_TRAILER (1 << 9) +#define SPEEDY_RX_MODEBIT_ERR (1 << 16) +#define SPEEDY_RX_GLITCH_ERR (1 << 17) +#define SPEEDY_RX_ENDBIT_ERR (1 << 18) +#define SPEEDY_TX_LINE_BUSY_ERR (1 << 20) +#define SPEEDY_TX_STOPBIT_ERR (1 << 21) +#define SPEEDY_REMOTE_RESET_REQ_STAT (1 << 31) + +/* SPEEDY_FIFO_STATUS Register bits */ +#define SPEEDY_VALID_DATA_CNT (0 << 0) +#define SPEEDY_FIFO_FULL (1 << 5) +#define SPEEDY_FIFO_EMPTY (1 << 6) + +/* SPEEDY_PACKET_GAP_TIME Register bits */ +#define SPEEDY_FIFO_TX_ALMOST_EMPTY (1 << 4) +#define SPEEDY_FSM_INIT (1 << 1) +#define SPEEDY_FSM_TX_CMD (1 << 2) +#define SPEEDY_FSM_STANDBY (1 << 3) +#define SPEEDY_FSM_DATA (1 << 4) +#define SPEEDY_FSM_TIMEOUT (1 << 5) +#define SPEEDY_FSM_TRANS_DONE (1 << 6) +#define SPEEDY_FSM_IO_RX_STAT_MASK (3 << 7) +#define SPEEDY_FSM_IO_TX_IDLE (1 << 9) +#define SPEEDY_FSM_IO_TX_GET_PACKET (1 << 10) +#define SPEEDY_FSM_IO_TX_PACKET (1 << 11) +#define SPEEDY_FSM_IO_TX_DONE (1 << 12) + +#define SPEEDY_RX_LENGTH(n) ((n) << 0) +#define SPEEDY_TX_LENGTH(n) ((n) << 8) + +#define SPEEDY_SLAVE(x) ((x & 0xf) << 15) +#define SPEEDY_ADDRESS(x) ((x & 0xff) << 7) + +static int speedy_fifo_reset(unsigned long base) +{ + writel(SPEEDY_FIFO_RESET, (void *)(base + SPEEDY_FIFO_CTRL)); + /* TODO: Implement a proper delay func */ + for (volatile int i = 0; i < 1000; i++); + return 0; +} + +static int speedy_int_clear(unsigned long base) +{ + writel(0xFFFFFFFF, (void *)(base + SPEEDY_INT_STATUS)); + /* TODO: Implement a proper delay func */ + for (volatile int i = 0; i < 1000; i++); + return 0; +} + +int speedy_read(struct speedy_transaction *tr) +{ + int ret = speedy_fifo_reset(tr->base); + if (ret) + return ret; + + writel(SPEEDY_RX_LENGTH(1) | SPEEDY_TX_LENGTH(1), + (void *)(tr->base + SPEEDY_FIFO_CTRL)); + + unsigned int cmd = SPEEDY_ACCESS_RANDOM | SPEEDY_DIRECTION_READ | + SPEEDY_SLAVE(tr->slave) | SPEEDY_ADDRESS(tr->offset); + + writel(SPEEDY_TRANSFER_DONE | SPEEDY_FIFO_RX_ALMOST_FULL_EN | + SPEEDY_RX_FIFO_INT_TRAILER_EN | SPEEDY_RX_MODEBIT_ERR_EN | + SPEEDY_RX_GLITCH_ERR_EN | SPEEDY_RX_ENDBIT_ERR_EN | + SPEEDY_REMOTE_RESET_REQ_EN, + (void *)(tr->base + SPEEDY_INT_ENABLE)); + + speedy_int_clear(tr->base); + + writel(cmd, (void *)(tr->base + SPEEDY_CMD)); + + // Poll for completion + int timeout = 500000; + while (timeout-- > 0) { + unsigned int int_status; + int_status = readl((volatile uint32_t *)(tr->base + + SPEEDY_INT_STATUS)); + if (int_status & SPEEDY_TRANSFER_DONE) { + speedy_int_clear(tr->base); + tr->val = readl((volatile uint32_t *) + (tr->base + SPEEDY_RX_DATA)); + return 0; + } + } + + return -1; +} + +int speedy_write(struct speedy_transaction *tr) +{ + int ret = speedy_fifo_reset(tr->base); + if (ret) + return ret; + + writel(SPEEDY_RX_LENGTH(1) | SPEEDY_TX_LENGTH(1), + (void *)(tr->base + SPEEDY_FIFO_CTRL)); + + unsigned int cmd = SPEEDY_ACCESS_RANDOM | SPEEDY_DIRECTION_WRITE | + SPEEDY_SLAVE(tr->slave) | SPEEDY_ADDRESS(tr->offset); + + writel(SPEEDY_TRANSFER_DONE_EN | SPEEDY_FIFO_TX_ALMOST_EMPTY_EN | + SPEEDY_TX_LINE_BUSY_ERR_EN | SPEEDY_TX_STOPBIT_ERR_EN | + SPEEDY_REMOTE_RESET_REQ_EN, + (void *)(tr->base + SPEEDY_INT_ENABLE)); + + speedy_int_clear(tr->base); + + writel(cmd, (void *)(tr->base + SPEEDY_CMD)); + writel(tr->val, (void *)(tr->base + SPEEDY_TX_DATA)); + + // Poll for completion + int timeout = 500000; + while (timeout-- > 0) { + unsigned int int_status; + int_status = readl((volatile uint32_t *)(tr->base + + SPEEDY_INT_STATUS)); + if (int_status & SPEEDY_TRANSFER_DONE) { + speedy_int_clear(tr->base); + return 0; + } + } + + return -1; +} diff --git a/include/drivers/samsung/exynos-speedy.h b/include/drivers/samsung/exynos-speedy.h new file mode 100644 index 0000000..d14741a --- /dev/null +++ b/include/drivers/samsung/exynos-speedy.h @@ -0,0 +1,22 @@ +/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) */ +/* + * Copyright (c) 2024 Ivaylo Ivanov + * Copyright (c) 2024 Markuss Broks + * + * Bindings for exynos-speedy + */ + +#ifndef EXYNOS_SPEEDY_H_ +#define EXYNOS_SPEEDY_H_ + +struct speedy_transaction { + unsigned long base; + unsigned int slave; + unsigned int offset; + unsigned int val; +}; + +extern int speedy_read(struct speedy_transaction *tr); +extern int speedy_write(struct speedy_transaction *tr); + +#endif /* EXYNOS_SPEEDY_H_ */ diff --git a/lib/unic/string.c b/lib/unic/string.c index 2aedef7..237bb69 100644 --- a/lib/unic/string.c +++ b/lib/unic/string.c @@ -216,3 +216,8 @@ void writel(unsigned int value, void* address) volatile unsigned int* ptr = (volatile unsigned int*)address; *ptr = value; } + +uint32_t readl(volatile uint32_t *addr) +{ + return *addr; +} diff --git a/lib/unic/string.h b/lib/unic/string.h index 1410334..becf476 100644 --- a/lib/unic/string.h +++ b/lib/unic/string.h @@ -7,6 +7,7 @@ #define STRING_H_ #include "stddef.h" +#include "stdint.h" #define LBLOCKSIZE (sizeof(long)) #define UNALIGNED(X) ((long)X & (LBLOCKSIZE - 1)) @@ -26,6 +27,7 @@ char *strchr (const char *s, int c); char *strrchr (const char *s, int c); long atol (const char *s); void writel (unsigned int value, void* address); +uint32_t readl(volatile uint32_t *addr); // C-driven optimized functions void *memset (void *m, int c, size_t n); @@ -37,6 +39,7 @@ void *memset (void *m, int c, size_t n); /* How many bytes are copied each iteration of the 4X unrolled loop. */ #define BIGBLOCKSIZE (sizeof(long) << 2) +static void *__optimized_memcpy (void *dst0, const void *src0, size_t len0) __attribute__((unused)); static void *__optimized_memcpy (void *dst0, const void *src0, size_t len0) { char *dst = dst0; @@ -63,9 +66,9 @@ static void *__optimized_memcpy (void *dst0, const void *src0, size_t len0) len0 -= LBLOCKSIZE; } - /* Pick up any residual with a byte copier. */ - dst = (char*)aligned_dst; - src = (char*)aligned_src; + /* Pick up any residual with a byte copier. */ + dst = (char*)aligned_dst; + src = (char*)aligned_src; } while (len0--)