From 99c7cc58e12d59a7562c637b7c1510cfdf33e4f9 Mon Sep 17 00:00:00 2001 From: Ye Li Date: Tue, 26 Jul 2022 16:41:07 +0800 Subject: ddr: imx: Add i.MX9 DDR controller driver Since i.MX9 uses same DDR PHY with i.MX8M, split the DDRPHY to a common directory under imx, then use dedicated ddr controller driver for each iMX9 and iMX8M. The DDRPHY registers are space compressed, so it needs conversion to access the DDRPHY address. Introduce a common PHY address remap function for both iMX8M and iMX9 for all PHY registers accessing. Signed-off-by: Ye Li Signed-off-by: Peng Fan --- drivers/ddr/imx/phy/ddrphy_utils.c | 169 +++++++++++++++++++++++++++++++++++++ 1 file changed, 169 insertions(+) create mode 100644 drivers/ddr/imx/phy/ddrphy_utils.c (limited to 'drivers/ddr/imx/phy/ddrphy_utils.c') diff --git a/drivers/ddr/imx/phy/ddrphy_utils.c b/drivers/ddr/imx/phy/ddrphy_utils.c new file mode 100644 index 00000000000..b852c870f90 --- /dev/null +++ b/drivers/ddr/imx/phy/ddrphy_utils.c @@ -0,0 +1,169 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright 2018 NXP + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +static inline void poll_pmu_message_ready(void) +{ + unsigned int reg; + + do { + reg = reg32_read(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + ddrphy_addr_remap(0xd0004)); + } while (reg & 0x1); +} + +static inline void ack_pmu_message_receive(void) +{ + unsigned int reg; + + reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + ddrphy_addr_remap(0xd0031), 0x0); + + do { + reg = reg32_read(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + ddrphy_addr_remap(0xd0004)); + } while (!(reg & 0x1)); + + reg32_write(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + ddrphy_addr_remap(0xd0031), 0x1); +} + +static inline unsigned int get_mail(void) +{ + unsigned int reg; + + poll_pmu_message_ready(); + + reg = reg32_read(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + ddrphy_addr_remap(0xd0032)); + + ack_pmu_message_receive(); + + return reg; +} + +static inline unsigned int get_stream_message(void) +{ + unsigned int reg, reg2; + + poll_pmu_message_ready(); + + reg = reg32_read(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + ddrphy_addr_remap(0xd0032)); + + reg2 = reg32_read(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + ddrphy_addr_remap(0xd0034)); + + reg2 = (reg2 << 16) | reg; + + ack_pmu_message_receive(); + + return reg2; +} + +static inline void decode_major_message(unsigned int mail) +{ + debug("[PMU Major message = 0x%08x]\n", mail); +} + +static inline void decode_streaming_message(void) +{ + unsigned int string_index, arg __maybe_unused; + int i = 0; + + string_index = get_stream_message(); + debug("PMU String index = 0x%08x\n", string_index); + while (i < (string_index & 0xffff)) { + arg = get_stream_message(); + debug("arg[%d] = 0x%08x\n", i, arg); + i++; + } + + debug("\n"); +} + +int wait_ddrphy_training_complete(void) +{ + unsigned int mail; + + while (1) { + mail = get_mail(); + decode_major_message(mail); + if (mail == 0x08) { + decode_streaming_message(); + } else if (mail == 0x07) { + debug("Training PASS\n"); + return 0; + } else if (mail == 0xff) { + printf("Training FAILED\n"); + return -1; + } + } +} + +void ddrphy_init_set_dfi_clk(unsigned int drate) +{ + switch (drate) { + case 4000: + dram_pll_init(MHZ(1000)); + dram_disable_bypass(); + break; + case 3733: + dram_pll_init(MHZ(933)); + dram_disable_bypass(); + break; + case 3200: + dram_pll_init(MHZ(800)); + dram_disable_bypass(); + break; + case 3000: + dram_pll_init(MHZ(750)); + dram_disable_bypass(); + break; + case 2800: + dram_pll_init(MHZ(700)); + dram_disable_bypass(); + break; + case 2400: + dram_pll_init(MHZ(600)); + dram_disable_bypass(); + break; + case 1866: + dram_pll_init(MHZ(466)); + dram_disable_bypass(); + break; + case 1600: + dram_pll_init(MHZ(400)); + dram_disable_bypass(); + break; + case 1066: + dram_pll_init(MHZ(266)); + dram_disable_bypass(); + break; + case 667: + dram_pll_init(MHZ(167)); + dram_disable_bypass(); + break; + case 400: + dram_enable_bypass(MHZ(400)); + break; + case 333: + dram_enable_bypass(MHZ(333)); + break; + case 200: + dram_enable_bypass(MHZ(200)); + break; + case 100: + dram_enable_bypass(MHZ(100)); + break; + default: + return; + } +} + +void ddrphy_init_read_msg_block(enum fw_type type) +{ +} -- cgit v1.2.3