Skip to content

Commit b38dc5e

Browse files
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 <[email protected]>
1 parent 8a4bb18 commit b38dc5e

File tree

11 files changed

+422
-0
lines changed

11 files changed

+422
-0
lines changed

boards/adi/max32690evkit/max32690evkit_max32690_m4.dts

+25
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
#include <adi/max32/max32690.dtsi>
1010
#include <adi/max32/max32690-pinctrl.dtsi>
1111
#include <zephyr/dt-bindings/gpio/adi-max32-gpio.h>
12+
#include <zephyr/dt-bindings/memory-controller/adi-max32-hpb.h>
1213
#include <zephyr/dt-bindings/input/input-event-codes.h>
1314
#include <zephyr/dt-bindings/mipi_dbi/mipi_dbi.h>
1415

@@ -95,6 +96,30 @@
9596
mosi-gpios = <&gpio2 24 (GPIO_ACTIVE_HIGH | MAX32_GPIO_VSEL_VDDIOH)>;
9697
cs-gpios = <&gpio2 11 (GPIO_ACTIVE_LOW | MAX32_GPIO_VSEL_VDDIOH)>;
9798
};
99+
100+
sdram1: sdram1@60000000 {
101+
compatible = "zephyr,memory-region", "mmio-sram";
102+
status = "disabled";
103+
device_type = "memory";
104+
reg = <0x60000000 DT_SIZE_M(8)>;
105+
zephyr,memory-region = "SDRAM1";
106+
};
107+
};
108+
109+
&hpb {
110+
pinctrl-0 = <&hyp_cs0n_p1_11 &hyp_rwds_p1_14 &hyp_d0_p1_12 &hyp_d1_p1_15
111+
&hyp_d2_p1_19 &hyp_d3_p1_20 &hyp_d4_p1_13
112+
&hyp_d5_p1_16 &hyp_d6_p1_18 &hyp_d7_p1_21>;
113+
pinctrl-names = "default";
114+
enable-emcc;
115+
116+
mem@0 {
117+
reg = <0>;
118+
base-address = <0x60000000>;
119+
device-type = <ADI_MAX32_HPB_DEV_TYPE_HYPER_RAM>;
120+
config-regs = <1>;
121+
config-reg-vals = <2>;
122+
};
98123
};
99124

100125
&clk_ipo {

boards/adi/max32690evkit/max32690evkit_max32690_m4.yaml

+1
Original file line numberDiff line numberDiff line change
@@ -21,5 +21,6 @@ supported:
2121
- w1
2222
- flash
2323
- usbd
24+
- memc
2425
ram: 1024
2526
flash: 3072

drivers/memc/CMakeLists.txt

+1
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ zephyr_library_sources_ifdef(CONFIG_MEMC_MCUX_FLEXSPI_APS6404L memc_mcux_flexspi
1616
zephyr_library_sources_ifdef(CONFIG_MEMC_MCUX_FLEXSPI_IS66WVQ8M4 memc_mcux_flexspi_is66wvq8m4.c)
1717
zephyr_library_sources_ifdef(CONFIG_MEMC_NXP_FLEXRAM memc_nxp_flexram.c)
1818
zephyr_library_sources_ifdef(CONFIG_MEMC_RENESAS_RA_SDRAM memc_renesas_ra_sdram.c)
19+
zephyr_library_sources_ifdef(CONFIG_MEMC_MAX32_HPB memc_max32_hpb.c)
1920

2021
zephyr_library_sources_ifdef(CONFIG_MEMC_SAM_SMC memc_sam_smc.c)
2122

drivers/memc/Kconfig

+2
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,8 @@ source "drivers/memc/Kconfig.mspi"
3434

3535
source "drivers/memc/Kconfig.renesas_ra"
3636

37+
source "drivers/memc/Kconfig.max32_hpb"
38+
3739
module = MEMC
3840
module-str = memc
3941
source "subsys/logging/Kconfig.template.log_config"

drivers/memc/Kconfig.max32_hpb

+10
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
# Copyright (c) 2025 Analog Devices, Inc
2+
# SPDX-License-Identifier: Apache-2.0
3+
4+
config MEMC_MAX32_HPB
5+
bool "MAX32 HyperBus"
6+
default y
7+
depends on DT_HAS_ADI_MAX32_HPB_ENABLED
8+
select PINCTRL
9+
help
10+
Enable ADI MAX32 HyperBus controller.

drivers/memc/memc_max32_hpb.c

+140
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,140 @@
1+
/*
2+
* Copyright (c) 2025 Analog Devices, Inc.
3+
*
4+
* SPDX-License-Identifier: Apache-2.0
5+
*/
6+
7+
#include <zephyr/device.h>
8+
#include <soc.h>
9+
10+
#include <zephyr/drivers/clock_control/adi_max32_clock_control.h>
11+
#include <zephyr/drivers/pinctrl.h>
12+
13+
#include <zephyr/logging/log.h>
14+
15+
LOG_MODULE_REGISTER(memc_max32_hpb, CONFIG_MEMC_LOG_LEVEL);
16+
17+
#include <hpb.h>
18+
#include <emcc.h>
19+
20+
#define DT_DRV_COMPAT adi_max32_hpb
21+
22+
struct memc_max32_hpb_config {
23+
const struct device *clock;
24+
const struct pinctrl_dev_config *pcfg;
25+
};
26+
27+
struct memc_max32_hpb_mem_config {
28+
uint8_t reg;
29+
30+
mxc_hpb_mem_config_t config;
31+
};
32+
33+
/* clang-format off */
34+
35+
#define MEM_CONFIG(n) \
36+
{ \
37+
.reg = DT_REG_ADDR(n), \
38+
.config = {.device_type = DT_PROP(n, device_type), \
39+
.base_addr = DT_PROP(n, base_address), \
40+
.latency_cycle = DT_PROP_OR(n, latency_cycles, 1), \
41+
.write_cs_high = DT_PROP_OR(n, write_cs_high, 0), \
42+
.read_cs_high = DT_PROP_OR(n, read_cs_high, 0), \
43+
.write_cs_hold = DT_PROP_OR(n, write_cs_hold, 0), \
44+
.read_cs_hold = DT_PROP_OR(n, read_cs_hold, 0), \
45+
.write_cs_setup = DT_PROP_OR(n, write_cs_setup, 0), \
46+
.read_cs_setup = DT_PROP_OR(n, read_cs_setup, 0), \
47+
.fixed_latency = DT_PROP_OR(n, fixed_read_latency, 0), \
48+
COND_CODE_1(DT_NODE_HAS_PROP(n, config_regs), \
49+
(.cfg_reg_val = config_regs_##n, \
50+
.cfg_reg_val_len = ARRAY_SIZE(config_regs_##n)), ()) }, \
51+
}
52+
53+
/* clang-format on */
54+
55+
#define CR_ENTRY(idx, n) \
56+
{ \
57+
.addr = DT_PROP_BY_IDX(n, config_regs, idx), \
58+
.val = DT_PROP_BY_IDX(n, config_reg_vals, idx), \
59+
}
60+
61+
#define MEM_CR_ENTRIES(n) \
62+
COND_CODE_1(DT_NODE_HAS_PROP(n, config_regs), ( \
63+
BUILD_ASSERT(DT_PROP_LEN(n, config_regs) == DT_PROP_LEN(n, config_reg_vals), \
64+
"The config-regs and config-reg-vals properties of adi,max32-hpb memory device" \
65+
" child nodes must be the same length"); \
66+
static const mxc_hpb_cfg_reg_val_t config_regs_##n[] = \
67+
{ LISTIFY(DT_PROP_LEN(n, config_regs), CR_ENTRY, (,), n) }; \
68+
), ())
69+
70+
/** memory device configuration(s). */
71+
DT_INST_FOREACH_CHILD(0, MEM_CR_ENTRIES)
72+
73+
/* clang-format off */
74+
75+
static const struct memc_max32_hpb_mem_config mem_configs[] = {
76+
DT_INST_FOREACH_CHILD_SEP(0, MEM_CONFIG, (,))};
77+
78+
#define CLOCK_CFG(node_id, prop, idx) \
79+
{.bus = DT_CLOCKS_CELL_BY_IDX(node_id, idx, offset), \
80+
.bit = DT_CLOCKS_CELL_BY_IDX(node_id, idx, bit)}
81+
82+
static const struct max32_perclk perclks[] = {
83+
DT_INST_FOREACH_PROP_ELEM_SEP(0, clocks, CLOCK_CFG, (,))};
84+
85+
/* clang-format on */
86+
static int memc_max32_hpb_init(const struct device *dev)
87+
{
88+
const struct memc_max32_hpb_config *config = dev->config;
89+
90+
int r;
91+
const mxc_hpb_mem_config_t *mem0 = NULL, *mem1 = NULL;
92+
93+
if (!device_is_ready(config->clock)) {
94+
LOG_ERR("clock control device not ready");
95+
return -ENODEV;
96+
}
97+
98+
for (size_t i = 0; i < ARRAY_SIZE(perclks); i++) {
99+
r = clock_control_on(config->clock, (clock_control_subsys_t)&perclks[i]);
100+
if (r < 0) {
101+
LOG_ERR("Could not initialize HPB clock (%d)", r);
102+
return r;
103+
}
104+
}
105+
106+
for (size_t i = 0; i < ARRAY_SIZE(mem_configs); i++) {
107+
if (mem_configs[i].reg == 0) {
108+
mem0 = &mem_configs[i].config;
109+
} else if (mem_configs[i].reg == 1) {
110+
mem1 = &mem_configs[i].config;
111+
}
112+
}
113+
114+
/* configure pinmux */
115+
r = pinctrl_apply_state(config->pcfg, PINCTRL_STATE_DEFAULT);
116+
if (r < 0) {
117+
LOG_ERR("HPB pinctrl setup failed (%d)", r);
118+
return r;
119+
}
120+
121+
r = MXC_HPB_Init(mem0, mem1);
122+
if (r < 0) {
123+
LOG_ERR("HPB init failed (%d)", r);
124+
return r;
125+
}
126+
127+
COND_CODE_1(DT_INST_PROP(0, enable_emcc), (MXC_EMCC_Enable()), (MXC_EMCC_Disable()));
128+
129+
return 0;
130+
}
131+
132+
PINCTRL_DT_INST_DEFINE(0);
133+
134+
static const struct memc_max32_hpb_config config = {
135+
.clock = DEVICE_DT_GET(DT_INST_CLOCKS_CTLR(0)),
136+
.pcfg = PINCTRL_DT_INST_DEV_CONFIG_GET(0),
137+
};
138+
139+
DEVICE_DT_INST_DEFINE(0, memc_max32_hpb_init, NULL, NULL, &config, POST_KERNEL,
140+
CONFIG_MEMC_INIT_PRIORITY, NULL);

dts/arm/adi/max32/max32690.dtsi

+9
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,15 @@
119119
};
120120
};
121121

122+
hpb: hpb@40039000 {
123+
compatible = "adi,max32-hpb";
124+
reg = <0x40039000 0x1000>;
125+
#address-cells = <1>;
126+
#size-cells = <0>;
127+
clocks = <&gcr ADI_MAX32_CLOCK_BUS1 4 &gcr ADI_MAX32_CLOCK_BUS1 7>;
128+
status = "disabled";
129+
};
130+
122131
spi0: spi@40046000 {
123132
compatible = "adi,max32-spi";
124133
reg = <0x40046000 0x1000>;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,154 @@
1+
# Copyright (c) 2025 Analog Devices, Inc.
2+
# SPDX-License-Identifier: Apache-2.0
3+
4+
description: |
5+
MAX32 HyperBus (HPB) Memory Controller Interface
6+
7+
The HyperBus and Xccela Memory Controller interface is a high-speed, low-pin
8+
count interface for connecting to one or more compatible external memory
9+
devices. The external HyperBus or Xccela Bus memory device is mapped into the
10+
memory space enabling direct code execution, data storage, or both.
11+
12+
The memory devices are defined as children of the HPB memory controller node.
13+
14+
&hpb {
15+
status = "okay";
16+
pinctrl-0 = <&hyp_cs0n_p1_11 &hyp_d0_p1_12 &hyp_d1_p1_15
17+
&hyp_d2_p1_19 &hyp_d3_p1_20 &hyp_d4_p1_13
18+
&hyp_d5_p1_16 &hyp_d6_p1_18 &hyp_d7_p1_21>;
19+
pinctrl-names = "default";
20+
21+
mem@0 {
22+
reg = <0>;
23+
base-address = <0x60000000>;
24+
device-type = <ADI_MAX32_HPB_DEV_TYPE_HYPER_RAM>;
25+
config-regs = <1>;
26+
config-reg-vals = <2>;
27+
};
28+
};
29+
30+
Note: the values for most properties take values from
31+
zephyr/dt-bindings/memory-controller/adi-max32-hpb.h header which will need to
32+
be included.
33+
34+
Finally, in order to make the memory available you will need to define new
35+
memory device/s in DeviceTree, e.g.:
36+
37+
sdram1: sdram@60000000 {
38+
compatible = "zephyr,memory-region", "mmio-sram";
39+
device_type = "memory";
40+
reg = <0x60000000 DT_SIZE_M(X)>;
41+
zephyr,memory-region = "SDRAM1";
42+
};
43+
44+
compatible: "adi,max32-hpb"
45+
46+
include: [base.yaml, pinctrl-device.yaml]
47+
48+
properties:
49+
reg:
50+
required: true
51+
52+
clocks:
53+
required: true
54+
55+
pinctrl-0:
56+
required: true
57+
58+
pinctrl-names:
59+
required: true
60+
61+
"#address-cells":
62+
required: true
63+
const: 1
64+
65+
"#size-cells":
66+
required: true
67+
const: 0
68+
69+
enable-emcc:
70+
type: boolean
71+
description: |
72+
Enable the EMCC cache controller for the HyperBus memory devices.
73+
74+
child-binding:
75+
description: Memory device.
76+
77+
properties:
78+
reg:
79+
type: int
80+
required: true
81+
82+
base-address:
83+
type: int
84+
description: |
85+
The address to which to map this memory device, e.g. 0x60000000. See the
86+
user guide for your specific SoC for the allowed range for mapping.
87+
88+
device-type:
89+
type: int
90+
required: true
91+
description: |
92+
The type of attached memory device, i.e. Hyper Flash, Xccela PSRAM, or
93+
Hyper RAM.
94+
95+
fixed-read-latency:
96+
type: boolean
97+
description: |
98+
Enable Xccela bus Fixed Read Latency. Should match the Latency Type
99+
configuration in the target PSRAM.
100+
101+
read-cs-high:
102+
type: int
103+
description: |
104+
The CS# high time, in clock cycles, between read operations.
105+
106+
write-cs-high:
107+
type: int
108+
description: |
109+
The CS# high time, in clock cycles, between write operations.
110+
111+
read-cs-setup:
112+
type: int
113+
description: |
114+
The CS# latency, in clock cycles, for read operations. This adds
115+
additional clock cycles after CS# goes low.
116+
117+
write-cs-setup:
118+
type: int
119+
description: |
120+
The CS# latency, in clock cycles, for write operations. This adds
121+
additional clock cycles after CS# goes low.
122+
123+
read-cs-hold:
124+
type: int
125+
description: |
126+
The CS# hold time, in clock cycles, between the completion of a read
127+
operation and the CS# deassertion.
128+
129+
write-cs-hold:
130+
type: int
131+
description: |
132+
The CS# hold time, in clock cycles, between the completion of a write
133+
operation and the CS# deassertion.
134+
135+
latency-cycles:
136+
type: int
137+
description: |
138+
For HyperRAM: set this property to match the external HyperRAM Read
139+
Latency Configuration Register value.
140+
141+
For Xccela PSRAM: The value is adjusted based on `fixed-read-latency`
142+
property also being set.
143+
144+
config-regs:
145+
type: array
146+
description: |
147+
Configuration register addresses to set on the memory device during
148+
initialization.
149+
150+
config-reg-vals:
151+
type: array
152+
description: |
153+
Configuration register values to set on the memory device during
154+
initialization.

0 commit comments

Comments
 (0)