Browse Source

drivers: memc: Add MAX32 HyperBus driver

Add memc driver for the MAX32 HyperBus peripheral, supporting HyperRAM
and Xccela PSRAM memory devices.

Signed-off-by: Pete Johanson <pete.johanson@analog.com>
pull/89409/head
Pete Johanson 4 months ago committed by Benjamin Cabé
parent
commit
f4b52a43d9
  1. 25
      boards/adi/max32690evkit/max32690evkit_max32690_m4.dts
  2. 1
      boards/adi/max32690evkit/max32690evkit_max32690_m4.yaml
  3. 1
      drivers/memc/CMakeLists.txt
  4. 2
      drivers/memc/Kconfig
  5. 10
      drivers/memc/Kconfig.max32_hpb
  6. 140
      drivers/memc/memc_max32_hpb.c
  7. 9
      dts/arm/adi/max32/max32690.dtsi
  8. 154
      dts/bindings/memory-controllers/adi,max32-hpb.yaml
  9. 53
      include/zephyr/dt-bindings/memory-controller/adi-max32-hpb.h
  10. 21
      tests/drivers/memc/ram/boards/max32690evkit_max32690_m4.overlay
  11. 6
      tests/drivers/memc/ram/testcase.yaml

25
boards/adi/max32690evkit/max32690evkit_max32690_m4.dts

@ -9,6 +9,7 @@ @@ -9,6 +9,7 @@
#include <adi/max32/max32690.dtsi>
#include <adi/max32/max32690-pinctrl.dtsi>
#include <zephyr/dt-bindings/gpio/adi-max32-gpio.h>
#include <zephyr/dt-bindings/memory-controller/adi-max32-hpb.h>
#include <zephyr/dt-bindings/input/input-event-codes.h>
#include <zephyr/dt-bindings/mipi_dbi/mipi_dbi.h>
@ -95,6 +96,30 @@ @@ -95,6 +96,30 @@
mosi-gpios = <&gpio2 24 (GPIO_ACTIVE_HIGH | MAX32_GPIO_VSEL_VDDIOH)>;
cs-gpios = <&gpio2 11 (GPIO_ACTIVE_LOW | MAX32_GPIO_VSEL_VDDIOH)>;
};
sdram1: sdram1@60000000 {
compatible = "zephyr,memory-region", "mmio-sram";
status = "disabled";
device_type = "memory";
reg = <0x60000000 DT_SIZE_M(8)>;
zephyr,memory-region = "SDRAM1";
};
};
&hpb {
pinctrl-0 = <&hyp_cs0n_p1_11 &hyp_rwds_p1_14 &hyp_d0_p1_12 &hyp_d1_p1_15
&hyp_d2_p1_19 &hyp_d3_p1_20 &hyp_d4_p1_13
&hyp_d5_p1_16 &hyp_d6_p1_18 &hyp_d7_p1_21>;
pinctrl-names = "default";
enable-emcc;
mem@0 {
reg = <0>;
base-address = <0x60000000>;
device-type = <ADI_MAX32_HPB_DEV_TYPE_HYPER_RAM>;
config-regs = <1>;
config-reg-vals = <2>;
};
};
&clk_ipo {

1
boards/adi/max32690evkit/max32690evkit_max32690_m4.yaml

@ -21,5 +21,6 @@ supported: @@ -21,5 +21,6 @@ supported:
- w1
- flash
- usbd
- memc
ram: 1024
flash: 3072

1
drivers/memc/CMakeLists.txt

@ -16,6 +16,7 @@ zephyr_library_sources_ifdef(CONFIG_MEMC_MCUX_FLEXSPI_APS6408L memc_mcux_flexspi @@ -16,6 +16,7 @@ zephyr_library_sources_ifdef(CONFIG_MEMC_MCUX_FLEXSPI_APS6408L memc_mcux_flexspi
zephyr_library_sources_ifdef(CONFIG_MEMC_MCUX_FLEXSPI_APS6404L memc_mcux_flexspi_aps6404l.c)
zephyr_library_sources_ifdef(CONFIG_MEMC_MCUX_FLEXSPI_IS66WVQ8M4 memc_mcux_flexspi_is66wvq8m4.c)
zephyr_library_sources_ifdef(CONFIG_MEMC_RENESAS_RA_SDRAM memc_renesas_ra_sdram.c)
zephyr_library_sources_ifdef(CONFIG_MEMC_MAX32_HPB memc_max32_hpb.c)
zephyr_library_sources_ifdef(CONFIG_MEMC_SAM_SMC memc_sam_smc.c)

2
drivers/memc/Kconfig

@ -34,6 +34,8 @@ source "drivers/memc/Kconfig.mspi" @@ -34,6 +34,8 @@ source "drivers/memc/Kconfig.mspi"
source "drivers/memc/Kconfig.renesas_ra"
source "drivers/memc/Kconfig.max32_hpb"
module = MEMC
module-str = memc
source "subsys/logging/Kconfig.template.log_config"

10
drivers/memc/Kconfig.max32_hpb

@ -0,0 +1,10 @@ @@ -0,0 +1,10 @@
# Copyright (c) 2025 Analog Devices, Inc
# SPDX-License-Identifier: Apache-2.0
config MEMC_MAX32_HPB
bool "MAX32 HyperBus"
default y
depends on DT_HAS_ADI_MAX32_HPB_ENABLED
select PINCTRL
help
Enable ADI MAX32 HyperBus controller.

140
drivers/memc/memc_max32_hpb.c

@ -0,0 +1,140 @@ @@ -0,0 +1,140 @@
/*
* Copyright (c) 2025 Analog Devices, Inc.
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <zephyr/device.h>
#include <soc.h>
#include <zephyr/drivers/clock_control/adi_max32_clock_control.h>
#include <zephyr/drivers/pinctrl.h>
#include <zephyr/logging/log.h>
LOG_MODULE_REGISTER(memc_max32_hpb, CONFIG_MEMC_LOG_LEVEL);
#include <hpb.h>
#include <emcc.h>
#define DT_DRV_COMPAT adi_max32_hpb
struct memc_max32_hpb_config {
const struct device *clock;
const struct pinctrl_dev_config *pcfg;
};
struct memc_max32_hpb_mem_config {
uint8_t reg;
mxc_hpb_mem_config_t config;
};
/* clang-format off */
#define MEM_CONFIG(n) \
{ \
.reg = DT_REG_ADDR(n), \
.config = {.device_type = DT_PROP(n, device_type), \
.base_addr = DT_PROP(n, base_address), \
.latency_cycle = DT_PROP_OR(n, latency_cycles, 1), \
.write_cs_high = DT_PROP_OR(n, write_cs_high, 0), \
.read_cs_high = DT_PROP_OR(n, read_cs_high, 0), \
.write_cs_hold = DT_PROP_OR(n, write_cs_hold, 0), \
.read_cs_hold = DT_PROP_OR(n, read_cs_hold, 0), \
.write_cs_setup = DT_PROP_OR(n, write_cs_setup, 0), \
.read_cs_setup = DT_PROP_OR(n, read_cs_setup, 0), \
.fixed_latency = DT_PROP_OR(n, fixed_read_latency, 0), \
COND_CODE_1(DT_NODE_HAS_PROP(n, config_regs), \
(.cfg_reg_val = config_regs_##n, \
.cfg_reg_val_len = ARRAY_SIZE(config_regs_##n)), ()) }, \
}
/* clang-format on */
#define CR_ENTRY(idx, n) \
{ \
.addr = DT_PROP_BY_IDX(n, config_regs, idx), \
.val = DT_PROP_BY_IDX(n, config_reg_vals, idx), \
}
#define MEM_CR_ENTRIES(n) \
COND_CODE_1(DT_NODE_HAS_PROP(n, config_regs), ( \
BUILD_ASSERT(DT_PROP_LEN(n, config_regs) == DT_PROP_LEN(n, config_reg_vals), \
"The config-regs and config-reg-vals properties of adi,max32-hpb memory device" \
" child nodes must be the same length"); \
static const mxc_hpb_cfg_reg_val_t config_regs_##n[] = \
{ LISTIFY(DT_PROP_LEN(n, config_regs), CR_ENTRY, (,), n) }; \
), ())
/** memory device configuration(s). */
DT_INST_FOREACH_CHILD(0, MEM_CR_ENTRIES)
/* clang-format off */
static const struct memc_max32_hpb_mem_config mem_configs[] = {
DT_INST_FOREACH_CHILD_SEP(0, MEM_CONFIG, (,))};
#define CLOCK_CFG(node_id, prop, idx) \
{.bus = DT_CLOCKS_CELL_BY_IDX(node_id, idx, offset), \
.bit = DT_CLOCKS_CELL_BY_IDX(node_id, idx, bit)}
static const struct max32_perclk perclks[] = {
DT_INST_FOREACH_PROP_ELEM_SEP(0, clocks, CLOCK_CFG, (,))};
/* clang-format on */
static int memc_max32_hpb_init(const struct device *dev)
{
const struct memc_max32_hpb_config *config = dev->config;
int r;
const mxc_hpb_mem_config_t *mem0 = NULL, *mem1 = NULL;
if (!device_is_ready(config->clock)) {
LOG_ERR("clock control device not ready");
return -ENODEV;
}
for (size_t i = 0; i < ARRAY_SIZE(perclks); i++) {
r = clock_control_on(config->clock, (clock_control_subsys_t)&perclks[i]);
if (r < 0) {
LOG_ERR("Could not initialize HPB clock (%d)", r);
return r;
}
}
for (size_t i = 0; i < ARRAY_SIZE(mem_configs); i++) {
if (mem_configs[i].reg == 0) {
mem0 = &mem_configs[i].config;
} else if (mem_configs[i].reg == 1) {
mem1 = &mem_configs[i].config;
}
}
/* configure pinmux */
r = pinctrl_apply_state(config->pcfg, PINCTRL_STATE_DEFAULT);
if (r < 0) {
LOG_ERR("HPB pinctrl setup failed (%d)", r);
return r;
}
r = MXC_HPB_Init(mem0, mem1);
if (r < 0) {
LOG_ERR("HPB init failed (%d)", r);
return r;
}
COND_CODE_1(DT_INST_PROP(0, enable_emcc), (MXC_EMCC_Enable()), (MXC_EMCC_Disable()));
return 0;
}
PINCTRL_DT_INST_DEFINE(0);
static const struct memc_max32_hpb_config config = {
.clock = DEVICE_DT_GET(DT_INST_CLOCKS_CTLR(0)),
.pcfg = PINCTRL_DT_INST_DEV_CONFIG_GET(0),
};
DEVICE_DT_INST_DEFINE(0, memc_max32_hpb_init, NULL, NULL, &config, POST_KERNEL,
CONFIG_MEMC_INIT_PRIORITY, NULL);

9
dts/arm/adi/max32/max32690.dtsi

@ -119,6 +119,15 @@ @@ -119,6 +119,15 @@
};
};
hpb: hpb@40039000 {
compatible = "adi,max32-hpb";
reg = <0x40039000 0x1000>;
#address-cells = <1>;
#size-cells = <0>;
clocks = <&gcr ADI_MAX32_CLOCK_BUS1 4 &gcr ADI_MAX32_CLOCK_BUS1 7>;
status = "disabled";
};
spi0: spi@40046000 {
compatible = "adi,max32-spi";
reg = <0x40046000 0x1000>;

154
dts/bindings/memory-controllers/adi,max32-hpb.yaml

@ -0,0 +1,154 @@ @@ -0,0 +1,154 @@
# Copyright (c) 2025 Analog Devices, Inc.
# SPDX-License-Identifier: Apache-2.0
description: |
MAX32 HyperBus (HPB) Memory Controller Interface
The HyperBus and Xccela Memory Controller interface is a high-speed, low-pin
count interface for connecting to one or more compatible external memory
devices. The external HyperBus or Xccela Bus memory device is mapped into the
memory space enabling direct code execution, data storage, or both.
The memory devices are defined as children of the HPB memory controller node.
&hpb {
status = "okay";
pinctrl-0 = <&hyp_cs0n_p1_11 &hyp_d0_p1_12 &hyp_d1_p1_15
&hyp_d2_p1_19 &hyp_d3_p1_20 &hyp_d4_p1_13
&hyp_d5_p1_16 &hyp_d6_p1_18 &hyp_d7_p1_21>;
pinctrl-names = "default";
mem@0 {
reg = <0>;
base-address = <0x60000000>;
device-type = <ADI_MAX32_HPB_DEV_TYPE_HYPER_RAM>;
config-regs = <1>;
config-reg-vals = <2>;
};
};
Note: the values for most properties take values from
zephyr/dt-bindings/memory-controller/adi-max32-hpb.h header which will need to
be included.
Finally, in order to make the memory available you will need to define new
memory device/s in DeviceTree, e.g.:
sdram1: sdram@60000000 {
compatible = "zephyr,memory-region", "mmio-sram";
device_type = "memory";
reg = <0x60000000 DT_SIZE_M(X)>;
zephyr,memory-region = "SDRAM1";
};
compatible: "adi,max32-hpb"
include: [base.yaml, pinctrl-device.yaml]
properties:
reg:
required: true
clocks:
required: true
pinctrl-0:
required: true
pinctrl-names:
required: true
"#address-cells":
required: true
const: 1
"#size-cells":
required: true
const: 0
enable-emcc:
type: boolean
description: |
Enable the EMCC cache controller for the HyperBus memory devices.
child-binding:
description: Memory device.
properties:
reg:
type: int
required: true
base-address:
type: int
description: |
The address to which to map this memory device, e.g. 0x60000000. See the
user guide for your specific SoC for the allowed range for mapping.
device-type:
type: int
required: true
description: |
The type of attached memory device, i.e. Hyper Flash, Xccela PSRAM, or
Hyper RAM.
fixed-read-latency:
type: boolean
description: |
Enable Xccela bus Fixed Read Latency. Should match the Latency Type
configuration in the target PSRAM.
read-cs-high:
type: int
description: |
The CS# high time, in clock cycles, between read operations.
write-cs-high:
type: int
description: |
The CS# high time, in clock cycles, between write operations.
read-cs-setup:
type: int
description: |
The CS# latency, in clock cycles, for read operations. This adds
additional clock cycles after CS# goes low.
write-cs-setup:
type: int
description: |
The CS# latency, in clock cycles, for write operations. This adds
additional clock cycles after CS# goes low.
read-cs-hold:
type: int
description: |
The CS# hold time, in clock cycles, between the completion of a read
operation and the CS# deassertion.
write-cs-hold:
type: int
description: |
The CS# hold time, in clock cycles, between the completion of a write
operation and the CS# deassertion.
latency-cycles:
type: int
description: |
For HyperRAM: set this property to match the external HyperRAM Read
Latency Configuration Register value.
For Xccela PSRAM: The value is adjusted based on `fixed-read-latency`
property also being set.
config-regs:
type: array
description: |
Configuration register addresses to set on the memory device during
initialization.
config-reg-vals:
type: array
description: |
Configuration register values to set on the memory device during
initialization.

53
include/zephyr/dt-bindings/memory-controller/adi-max32-hpb.h

@ -0,0 +1,53 @@ @@ -0,0 +1,53 @@
/*
* Copyright 2023 NXP
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef ZEPHYR_INCLUDE_DT_BINDINGS_MEMORY_CONTROLLER_ADI_MAX32_HPB_H_
#define ZEPHYR_INCLUDE_DT_BINDINGS_MEMORY_CONTROLLER_ADI_MAX32_HPB_H_
#define ADI_MAX32_HPB_CS_HIGH_1_5 0 /**< CS High 1.5 clock cycles */
#define ADI_MAX32_HPB_CS_HIGH_2_5 1 /**< CS High 2.5 clock cycles */
#define ADI_MAX32_HPB_CS_HIGH_3_5 2 /**< CS High 3.5 clock cycles */
#define ADI_MAX32_HPB_CS_HIGH_4_5 3 /**< CS High 4.5 clock cycles */
#define ADI_MAX32_HPB_CS_HIGH_5_5 4 /**< CS High 5.5 clock cycles */
#define ADI_MAX32_HPB_CS_HIGH_6_5 5 /**< CS High 6.5 clock cycles */
#define ADI_MAX32_HPB_CS_HIGH_7_5 6 /**< CS High 7.5 clock cycles */
#define ADI_MAX32_HPB_CS_HIGH_8_5 7 /**< CS High 8.5 clock cycles */
#define ADI_MAX32_HPB_CS_HIGH_9_5 8 /**< CS High 9.5 clock cycles */
#define ADI_MAX32_HPB_CS_HIGH_10_5 9 /**< CS High 10.5 clock cycles */
#define ADI_MAX32_HPB_CS_HIGH_11_5 10 /**< CS High 11.5 clock cycles */
#define ADI_MAX32_HPB_CS_HIGH_12_5 11 /**< CS High 12.5 clock cycles */
#define ADI_MAX32_HPB_CS_HIGH_13_5 12 /**< CS High 13.5 clock cycles */
#define ADI_MAX32_HPB_CS_HIGH_14_5 13 /**< CS High 14.5 clock cycles */
#define ADI_MAX32_HPB_CS_HIGH_15_5 14 /**< CS High 15.5 clock cycles */
#define ADI_MAX32_HPB_CS_HIGH_16_5 15 /**< CS High 16.5 clock cycles */
#define ADI_MAX32_HPB_CS_SETUP_HOLD_1 0 /**< CS Setup/Hold 1 clock cycles */
#define ADI_MAX32_HPB_CS_SETUP_HOLD_2 1 /**< CS Setup/Hold 2 clock cycles */
#define ADI_MAX32_HPB_CS_SETUP_HOLD_3 2 /**< CS Setup/Hold 3 clock cycles */
#define ADI_MAX32_HPB_CS_SETUP_HOLD_4 3 /**< CS Setup/Hold 4 clock cycles */
#define ADI_MAX32_HPB_CS_SETUP_HOLD_5 4 /**< CS Setup/Hold 5 clock cycles */
#define ADI_MAX32_HPB_CS_SETUP_HOLD_6 5 /**< CS Setup/Hold 6 clock cycles */
#define ADI_MAX32_HPB_CS_SETUP_HOLD_7 6 /**< CS Setup/Hold 7 clock cycles */
#define ADI_MAX32_HPB_CS_SETUP_HOLD_8 7 /**< CS Setup/Hold 8 clock cycles */
#define ADI_MAX32_HPB_CS_SETUP_HOLD_9 8 /**< CS Setup/Hold 9 clock cycles */
#define ADI_MAX32_HPB_CS_SETUP_HOLD_10 9 /**< CS Setup/Hold 10 clock cycles */
#define ADI_MAX32_HPB_CS_SETUP_HOLD_11 10 /**< CS Setup/Hold 11 clock cycles */
#define ADI_MAX32_HPB_CS_SETUP_HOLD_12 11 /**< CS Setup/Hold 12 clock cycles */
#define ADI_MAX32_HPB_CS_SETUP_HOLD_13 12 /**< CS Setup/Hold 13 clock cycles */
#define ADI_MAX32_HPB_CS_SETUP_HOLD_14 13 /**< CS Setup/Hold 14 clock cycles */
#define ADI_MAX32_HPB_CS_SETUP_HOLD_15 14 /**< CS Setup/Hold 15 clock cycles */
#define ADI_MAX32_HPB_CS_SETUP_HOLD_16 15 /**< CS Setup/Hold 16 clock cycles */
#define ADI_MAX32_HPB_LAT_5 0x0 /**< 5 clock latency for RAM */
#define ADI_MAX32_HPB_LAT_6 0x1 /**< 6 clock latency for RAM */
#define ADI_MAX32_HPB_LAT_3 0xE /**< 3 clock latency for RAM */
#define ADI_MAX32_HPB_LAT_4 0xF /**< 4 clock latency for RAM */
#define ADI_MAX32_HPB_DEV_TYPE_HYPER_FLASH 0
#define ADI_MAX32_HPB_DEV_TYPE_XCCELA_PSRAM 1
#define ADI_MAX32_HPB_DEV_TYPE_HYPER_RAM 2
#endif /* ZEPHYR_INCLUDE_DT_BINDINGS_MEMORY_CONTROLLER_ADI_MAX32_HPB_H_ */

21
tests/drivers/memc/ram/boards/max32690evkit_max32690_m4.overlay

@ -0,0 +1,21 @@ @@ -0,0 +1,21 @@
/*
* Copyright (c) 2025 Analog Devices, Inc.
*
* SPDX-License-Identifier: Apache-2.0
*/
&sram1 {
status = "disabled";
};
&sram2 {
status = "disabled";
};
&hpb {
status = "okay";
};
&sdram1 {
status = "okay";
};

6
tests/drivers/memc/ram/testcase.yaml

@ -34,3 +34,9 @@ tests: @@ -34,3 +34,9 @@ tests:
depends_on: memc
filter: dt_compat_enabled("renesas,ra-sdram")
platform_allow: ek_ra8d1
drivers.memc.max32_hpb:
tags:
- drivers
- memc
filter: dt_compat_enabled("adi,max32-hpb")
platform_allow: max32690evkit/max32690/m4

Loading…
Cancel
Save