diff --git a/lk2nd/aurora/rules.mk b/lk2nd/aurora/rules.mk new file mode 100644 index 00000000..3c97f9cd --- /dev/null +++ b/lk2nd/aurora/rules.mk @@ -0,0 +1,9 @@ +# SPDX-License-Identifier: BSD-3-Clause +# Aurora B9L (RAM test only): ST7735S SPI panel bring-up for the JZ08AU board (msm8916), stock-LK parameters. +# Uses the CAF spi_qup driver directly; platform/msm_shared/mdss_spi.o is deliberately NOT built (it is hard-wired +# to QM215/msm8909 and its presence would pull in lk2nd/device/2nd/spi-display.o, which dereferences a NULL panel.intf). +LOCAL_DIR := $(GET_LOCAL_DIR) + +OBJS += \ + platform/msm_shared/spi_qup.o \ + $(LOCAL_DIR)/st7735s.o \ diff --git a/lk2nd/aurora/st7735s.c b/lk2nd/aurora/st7735s.c new file mode 100644 index 00000000..8bfaeae3 --- /dev/null +++ b/lk2nd/aurora/st7735s.c @@ -0,0 +1,203 @@ +// SPDX-License-Identifier: BSD-3-Clause +/* + * Aurora JZ08AU (msm8916) ST7735S 128x128 SPI panel bring-up — B9L RAM test only. + * Every parameter is taken from the stock Aurora LK (aboot) analysis (logs/b9/b9a, logs/b9/lk): + * BLSP1 QUP4 (0x78b8000), 16 MHz, SPI mode 3 (CLK_IDLE_HIGH, INPUT_FIRST=0), CS0, TX only; + * D/C = GPIO116, RESET = GPIO118 (1, 0 for 1 ms, 1, wait 120 ms); the 19 stock init commands (ending with RAMWR); + * one RGB565 frame (16-bit words); backlight = PM8916 MPP4 current sink 40 mA (MODE 0x61, SINK 7, EN 0x80). + * No regulator is touched (stock LK has no regulator code either); L6/L17 state is only read and logged. + * The display is NOT registered with fbcon, so lk2nd's own display code cannot draw over the test frame. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#define DC_GPIO 116 +#define RST_GPIO 118 +#define W 128 +#define H 128 + +#define TLMM_CFG(n) (TLMM_BASE_ADDR + 0x1000 * (n)) +#define TLMM_IO(n) (TLMM_BASE_ADDR + 0x1000 * (n) + 4) + +static struct qup_spi_dev *dev; + +/* stock LK table @0x8f64849c == stock dtb_01 qcom,mdss-spi-on-command (b9/b9a/decode-panel.py) */ +static const struct { uint8_t len, wait; uint8_t d[17]; } cmds[] = { + { 1, 120, { 0x11 } }, + { 4, 0, { 0xb1, 0x05, 0x3a, 0x3a } }, + { 4, 0, { 0xb2, 0x05, 0x3a, 0x3a } }, + { 7, 0, { 0xb3, 0x05, 0x3a, 0x3a, 0x05, 0x3a, 0x3a } }, + { 2, 0, { 0xb4, 0x03 } }, + { 4, 0, { 0xc0, 0x62, 0x02, 0x04 } }, + { 2, 0, { 0xc1, 0xc0 } }, + { 3, 0, { 0xc2, 0x0d, 0x00 } }, + { 3, 0, { 0xc3, 0x8d, 0x6a } }, + { 3, 0, { 0xc4, 0x8d, 0xee } }, + { 2, 0, { 0xc5, 0x12 } }, + { 17, 0, { 0xe0, 0x03, 0x1b, 0x12, 0x11, 0x3f, 0x3a, 0x32, 0x34, 0x2f, 0x2b, 0x30, 0x3a, 0x00, 0x01, 0x02, 0x05 } }, + { 17, 0, { 0xe1, 0x03, 0x1b, 0x12, 0x11, 0x32, 0x2f, 0x2a, 0x2f, 0x2e, 0x2c, 0x35, 0x3f, 0x00, 0x00, 0x01, 0x05 } }, + { 2, 0, { 0x36, 0xc8 } }, + { 2, 0, { 0x3a, 0x05 } }, + { 5, 0, { 0x2a, 0x00, 0x02, 0x00, 0x81 } }, + { 5, 0, { 0x2b, 0x00, 0x03, 0x00, 0x82 } }, + { 1, 0, { 0x29 } }, + { 1, 0, { 0x2c } }, +}; + +static unsigned t0; +#define LOG(fmt, ...) dprintf(INFO, "[B9L +%u ms] " fmt "\n", (unsigned)(current_time() - t0), ##__VA_ARGS__) + +static int spi_cmd(uint8_t c) +{ + int ret; + dev->bytes_per_word = 1; + dev->bit_shift_en = 1; + gpio_set_dir(DC_GPIO, 0); /* D/C low = command */ + ret = spi_qup_write(dev, &c, 1); + gpio_set_dir(DC_GPIO, 2); + return ret; +} + +static int spi_data(const uint8_t *b, unsigned len) +{ + dev->bytes_per_word = 1; + dev->bit_shift_en = 1; + gpio_set_dir(DC_GPIO, 2); /* D/C high = parameters */ + return spi_qup_write(dev, b, len); +} + +static int spi_frame(const uint8_t *b, unsigned len) +{ + dev->bytes_per_word = 2; /* RGB565, little-endian u16 in memory, sent MSB first (as stock LK) */ + dev->bit_shift_en = 1; + dev->unpack_en = 0; + gpio_set_dir(DC_GPIO, 2); + return spi_qup_write(dev, b, len); +} + +static uint16_t rgb(uint8_t r, uint8_t g, uint8_t b) +{ + return (r >> 3) << 11 | (g >> 2) << 5 | b >> 3; +} + +/* same chart as the Linux B9B test: 1-px white border, R/G/B/W corners, R|G|B bars, yellow arrow up */ +static void draw_geo(uint16_t *p) +{ + const uint16_t R = rgb(255, 0, 0), G = rgb(0, 255, 0), B = rgb(0, 0, 255), Wh = rgb(255, 255, 255), Y = rgb(255, 255, 0); + int x, y; + + for (y = 0; y < H; y++) + for (x = 0; x < W; x++) { + uint16_t c = 0; + int ax = x * 2 - 127; /* 2*(x - 63.5) */ + if (x == 0 || x == W - 1 || y == 0 || y == H - 1) + c = Wh; + else if (x >= 2 && x < 26 && y >= 2 && y < 26) + c = R; + else if (x >= W - 26 && x < W - 2 && y >= 2 && y < 26) + c = G; + else if (x >= 2 && x < 26 && y >= H - 26 && y < H - 2) + c = B; + else if (x >= W - 26 && x < W - 2 && y >= H - 26 && y < H - 2) + c = Wh; + else if (y >= 40 && y < 88 && x >= 28 && x < 100) + c = (x - 28) < 24 ? R : (x - 28) < 48 ? G : B; + else if (y >= 6 && y < 22 && (ax < 0 ? -ax : ax) <= (y - 6)) + c = Y; + else if (y >= 22 && y < 34 && x >= 58 && x < 70) + c = Y; + p[y * W + x] = c; + } +} + +static void log_power(const char *when) +{ + /* PM8916 SID1: LDO6 0x4500, LDO17 0x5000 (08 STATUS, 46 EN_CTL); SID0: MPP4 0xa300 (40 MODE, 46 EN, 4c SINK) */ + LOG("%s: L6 st=%02x en=%02x L17 st=%02x en=%02x vset=%02x MPP4 mode=%02x en=%02x sink=%02x", when, + pm8x41_reg_read(0x14508), pm8x41_reg_read(0x14546), + pm8x41_reg_read(0x15008), pm8x41_reg_read(0x15046), pm8x41_reg_read(0x15041), + pm8x41_reg_read(0xa340), pm8x41_reg_read(0xa346), pm8x41_reg_read(0xa34c)); +} + +static void log_hw(const char *when) +{ + LOG("%s: TLMM cfg/io 12=%x/%x 13=%x 14=%x 15=%x 116=%x/%x 118=%x/%x QUP4 spi CBCR=%08x RCGR=%08x/%08x", when, + readl(TLMM_CFG(12)), readl(TLMM_IO(12)), readl(TLMM_CFG(13)), readl(TLMM_CFG(14)), readl(TLMM_CFG(15)), + readl(TLMM_CFG(DC_GPIO)), readl(TLMM_IO(DC_GPIO)), readl(TLMM_CFG(RST_GPIO)), readl(TLMM_IO(RST_GPIO)), + readl(CLK_CTL_BASE + 0x501C), readl(CLK_CTL_BASE + 0x5024), readl(CLK_CTL_BASE + 0x5028)); +} + +static void aurora_st7735s_init(void) +{ + uint16_t *fb; + unsigned i, fails = 0; + int ret; + + t0 = current_time(); + LOG("ST7735S bring-up start (stock Aurora parameters)"); + log_power("before"); + log_hw("before"); + + /* RESET GPIO118: func0 out 8 mA, OE; 1 -> 1 ms -> 0 -> 1 ms -> 1 -> 120 ms (stock target_panel_reset) */ + gpio_tlmm_config(RST_GPIO, 0, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_8MA, 1); + gpio_set_dir(RST_GPIO, 2); mdelay(1); + gpio_set_dir(RST_GPIO, 0); mdelay(1); + gpio_set_dir(RST_GPIO, 2); mdelay(120); + LOG("reset done (GPIO118 high)"); + + dev = qup_blsp_spi_init(BLSP_ID_1, QUP_ID_3); + if (!dev) { + LOG("FAIL: qup_blsp_spi_init(BLSP1, QUP_ID_3)"); + return; + } + dev->force_cs_dis = 1; /* stock SPI_IO_CONTROL = 0x401: NO_TRI_STATE | CLK_IDLE_HIGH, CS0, no FORCE_CS */ + /* D/C GPIO116: func0 out 8 mA, OE (stock) */ + gpio_tlmm_config(DC_GPIO, 0, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_8MA, 1); + gpio_set_dir(DC_GPIO, 2); + LOG("QUP4 SPI init done: base=0x%x", dev->qup_base); + log_hw("after QUP init"); + + for (i = 0; i < sizeof(cmds) / sizeof(cmds[0]); i++) { + ret = spi_cmd(cmds[i].d[0]); + if (!ret && cmds[i].len > 1) + ret = spi_data(&cmds[i].d[1], cmds[i].len - 1); + if (ret) { + fails++; + LOG("cmd %u (0x%02x) FAILED ret=%d", i, cmds[i].d[0], ret); + } + if (cmds[i].wait) + mdelay(cmds[i].wait); + } + LOG("19 init commands sent, %u failures; SPI_IO_CONTROL=%x SPI_CONFIG=%x", fails, + readl(dev->qup_base + SPI_IO_CONTROL), readl(dev->qup_base + SPI_CONFIG)); + + fb = memalign(64, W * H * 2); + if (!fb) { + LOG("FAIL: no memory for frame"); + return; + } + draw_geo(fb); + ret = spi_frame((const uint8_t *)fb, W * H * 2); + LOG("frame %ux%u RGB565 (%u bytes) sent ret=%d (fb @%p)", W, H, W * H * 2, ret, fb); + + /* backlight: PM8916 MPP4 current sink, exactly the stock LK target_backlight_ctrl writes */ + pm8x41_reg_write(0xa340, 0x61); + pm8x41_reg_write(0xa34c, 0x07); + pm8x41_reg_write(0xa346, 0x80); + mdelay(20); + log_power("after backlight"); + log_hw("end"); + LOG("ST7735S bring-up end - continuing lk2nd boot"); +} +LK2ND_INIT(aurora_st7735s_init); diff --git a/platform/msm8916/acpuclock.c b/platform/msm8916/acpuclock.c index 158ab395..b7533e6c 100644 --- a/platform/msm8916/acpuclock.c +++ b/platform/msm8916/acpuclock.c @@ -529,3 +529,39 @@ void clock_config_blsp_i2c(uint8_t blsp_id, uint8_t qup_id) return; } } + +/* + * Aurora B9L: SPI core clock, copied from msm8909 acpuclock.c. The CAF spi_qup driver always asks for MAX_SPEED_HZ + * (50 MHz, qup.h); the Aurora ST7735S panel runs at 16 MHz in stock LK (gcc_blsp1_qup4_spi_apps_clk = 16000000), + * so the rate is clamped here. + */ +#define AURORA_SPI_MAX_HZ 16000000 +void clock_config_blsp_spi(uint8_t blsp_id, uint8_t qup_id, unsigned long rate) +{ + uint8_t ret = 0; + char clk_name[64]; + + qup_id = qup_id + 1; + + if (blsp_id != BLSP_ID_1) { + dprintf(CRITICAL, "Incorrect BLSP-%d configuration\n", blsp_id); + ASSERT(0); + } + if (rate > AURORA_SPI_MAX_HZ) + rate = AURORA_SPI_MAX_HZ; + + snprintf(clk_name, sizeof(clk_name), "blsp1_ahb_iface_clk"); + ret = clk_get_set_enable(clk_name, 0, 1); + if (ret) { + dprintf(CRITICAL, "%s: Failed to enable %s clock\n", __func__, clk_name); + return; + } + + snprintf(clk_name, sizeof(clk_name), "gcc_blsp1_qup%u_spi_apps_clk", qup_id); + ret = clk_get_set_enable(clk_name, rate, 1); + if (ret) { + dprintf(CRITICAL, "%s: Failed to enable %s\n", __func__, clk_name); + return; + } + dprintf(INFO, "B9L: %s enabled at %lu Hz\n", clk_name, rate); +} diff --git a/platform/msm8916/gpio.c b/platform/msm8916/gpio.c index 145b81ce..2912792b 100644 --- a/platform/msm8916/gpio.c +++ b/platform/msm8916/gpio.c @@ -26,6 +26,7 @@ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +#include #include #include #include @@ -99,3 +100,19 @@ void gpio_config_blsp_i2c(uint8_t blsp_id, uint8_t qup_id) ASSERT(0); } } + +/* + * Aurora B9L: BLSP1 QUP4 (QUP_ID_3, 0x78b8000) SPI pins as in stock Aurora dtb_01 spi0_active/spi0_cs0_active: + * GPIO12 MOSI, GPIO13 MISO, GPIO15 CLK func 1, 12 mA, no pull; GPIO14 CS0 func 1 (native chip select), 2 mA, no pull. + */ +void gpio_config_blsp_spi(uint8_t blsp_id, uint8_t qup_id) +{ + if (blsp_id != BLSP_ID_1 || qup_id != QUP_ID_3) { + dprintf(CRITICAL, "Unsupported BLSP-%d QUP-%d SPI pin configuration\n", blsp_id, qup_id); + ASSERT(0); + } + gpio_tlmm_config(12, 1, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_12MA, GPIO_DISABLE); + gpio_tlmm_config(13, 1, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_12MA, GPIO_DISABLE); + gpio_tlmm_config(14, 1, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_2MA, GPIO_DISABLE); + gpio_tlmm_config(15, 1, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_12MA, GPIO_DISABLE); +} diff --git a/platform/msm8916/include/platform/clock.h b/platform/msm8916/include/platform/clock.h index fab62591..c0f00312 100644 --- a/platform/msm8916/include/platform/clock.h +++ b/platform/msm8916/include/platform/clock.h @@ -95,4 +95,5 @@ void gcc_dsi_clocks_disable(uint8_t dual_dsi); void clock_ce_enable(uint8_t instance); void clock_ce_disable(uint8_t instance); void clock_config_blsp_i2c(uint8_t blsp_id, uint8_t qup_id); +void clock_config_blsp_spi(uint8_t blsp_id, uint8_t qup_id, unsigned long rate); #endif diff --git a/platform/msm8916/include/platform/gpio.h b/platform/msm8916/include/platform/gpio.h index 0437aff4..ec4d5859 100644 --- a/platform/msm8916/include/platform/gpio.h +++ b/platform/msm8916/include/platform/gpio.h @@ -70,4 +70,5 @@ void gpio_tlmm_config(uint32_t gpio, uint8_t drvstr, uint32_t enable); void gpio_config_blsp_i2c(uint8_t blsp_id, uint8_t qup_id); +void gpio_config_blsp_spi(uint8_t blsp_id, uint8_t qup_id); #endif diff --git a/platform/msm8916/include/platform/iomap.h b/platform/msm8916/include/platform/iomap.h index 86a804bb..9e9e09d0 100644 --- a/platform/msm8916/include/platform/iomap.h +++ b/platform/msm8916/include/platform/iomap.h @@ -126,6 +126,13 @@ #define GCC_BLSP1_QUP4_APPS_CBCR (CLK_CTL_BASE + 0x5020) #define GCC_BLSP1_QUP4_CFG_RCGR (CLK_CTL_BASE + 0x5004) #define GCC_BLSP1_QUP4_CMD_RCGR (CLK_CTL_BASE + 0x5000) +/* Aurora B9L: BLSP1 QUP4 SPI clock (== msm8909 CAF, == Linux gcc-msm8916 0x5024/0x501c) */ +#define GCC_BLSP1_QUP4_SPI_APPS_CBCR (CLK_CTL_BASE + 0x501C) +#define GCC_BLSP1_QUP4_SPI_APPS_CMD_RCGR (CLK_CTL_BASE + 0x5024) +#define GCC_BLSP1_QUP4_SPI_CFG_RCGR (CLK_CTL_BASE + 0x5028) +#define GCC_BLSP1_QUP4_SPI_APPS_M (CLK_CTL_BASE + 0x502C) +#define GCC_BLSP1_QUP4_SPI_APPS_N (CLK_CTL_BASE + 0x5030) +#define GCC_BLSP1_QUP4_SPI_APPS_D (CLK_CTL_BASE + 0x5034) /* GPLL */ #define GPLL0_STATUS (CLK_CTL_BASE + 0x2101C) diff --git a/platform/msm8916/msm8916-clock.c b/platform/msm8916/msm8916-clock.c index a1b4b773..bec650a2 100644 --- a/platform/msm8916/msm8916-clock.c +++ b/platform/msm8916/msm8916-clock.c @@ -587,6 +587,45 @@ static struct branch_clk gcc_blsp1_qup4_i2c_apps_clk = { }, }; +/* Aurora B9L: BLSP1 QUP4 SPI clock, copied from msm8909-clock.c (freq table == Linux gcc-msm8916) */ +static struct clk_freq_tbl ftbl_gcc_blsp1_qup4_spi_apps_clk[] = { + F( 960000, cxo, 10, 1, 2), + F( 4800000, cxo, 4, 0, 0), + F( 9600000, cxo, 2, 0, 0), + F( 16000000, gpll0, 10, 1, 5), + F( 19200000, cxo, 1, 0, 0), + F( 25000000, gpll0, 16, 1, 2), + F( 50000000, gpll0, 16, 0, 0), + F_END +}; + +static struct rcg_clk gcc_blsp1_qup4_spi_apps_clk_src = +{ + .cmd_reg = (uint32_t *) GCC_BLSP1_QUP4_SPI_APPS_CMD_RCGR, + .cfg_reg = (uint32_t *) GCC_BLSP1_QUP4_SPI_CFG_RCGR, + .m_reg = (uint32_t *) GCC_BLSP1_QUP4_SPI_APPS_M, + .n_reg = (uint32_t *) GCC_BLSP1_QUP4_SPI_APPS_N, + .d_reg = (uint32_t *) GCC_BLSP1_QUP4_SPI_APPS_D, + .set_rate = clock_lib2_rcg_set_rate_mnd, + .freq_tbl = ftbl_gcc_blsp1_qup4_spi_apps_clk, + .current_freq = &rcg_dummy_freq, + + .c = { + .dbg_name = "gcc_blsp1_qup4_spi_apps_clk_src", + .ops = &clk_ops_rcg, + }, +}; + +static struct branch_clk gcc_blsp1_qup4_spi_apps_clk = { + .cbcr_reg = (uint32_t *) GCC_BLSP1_QUP4_SPI_APPS_CBCR, + .parent = &gcc_blsp1_qup4_spi_apps_clk_src.c, + + .c = { + .dbg_name = "gcc_blsp1_qup4_spi_apps_clk", + .ops = &clk_ops_branch, + }, +}; + /* Need different gpll0 source value for CPU clocks */ #undef gpll0_source_val #define gpll0_source_val 4 @@ -678,6 +717,9 @@ static struct clk_lookup msm_clocks_8916[] = CLK_LOOKUP("gcc_blsp1_qup2_i2c_apps_clk", gcc_blsp1_qup2_i2c_apps_clk.c), CLK_LOOKUP("blsp1_qup4_ahb_iface_clk", gcc_blsp1_ahb_clk.c), + CLK_LOOKUP("blsp1_ahb_iface_clk", gcc_blsp1_ahb_clk.c), /* Aurora B9L: name used by clock_config_blsp_spi */ + CLK_LOOKUP("gcc_blsp1_qup4_spi_apps_clk_src", gcc_blsp1_qup4_spi_apps_clk_src.c), + CLK_LOOKUP("gcc_blsp1_qup4_spi_apps_clk", gcc_blsp1_qup4_spi_apps_clk.c), CLK_LOOKUP("gcc_blsp1_qup4_i2c_apps_clk_src", gcc_blsp1_qup4_i2c_apps_clk_src.c), CLK_LOOKUP("gcc_blsp1_qup4_i2c_apps_clk", gcc_blsp1_qup4_i2c_apps_clk.c), diff --git a/project/lk2nd-msm8916.mk b/project/lk2nd-msm8916.mk index 192ae770..88c41f4d 100644 --- a/project/lk2nd-msm8916.mk +++ b/project/lk2nd-msm8916.mk @@ -1,3 +1,8 @@ # SPDX-License-Identifier: BSD-3-Clause TARGET := msm8916 include lk2nd/project/lk2nd.mk + +# Aurora B9L (RAM test only): ST7735S SPI panel bring-up module +ifeq ($(AURORA_SPI_PANEL),1) +MODULES += lk2nd/aurora +endif