1d00f779eSVadim Pasternak // SPDX-License-Identifier: GPL-2.0+
2d00f779eSVadim Pasternak /*
3d00f779eSVadim Pasternak * Nvidia Data Processor Unit platform driver
4d00f779eSVadim Pasternak *
5d00f779eSVadim Pasternak * Copyright (C) 2025 Nvidia Technologies Ltd.
6d00f779eSVadim Pasternak */
7d00f779eSVadim Pasternak
8d00f779eSVadim Pasternak #include <linux/device.h>
9d00f779eSVadim Pasternak #include <linux/dev_printk.h>
10d00f779eSVadim Pasternak #include <linux/i2c.h>
11d00f779eSVadim Pasternak #include <linux/module.h>
12d00f779eSVadim Pasternak #include <linux/platform_data/mlxcpld.h>
13d00f779eSVadim Pasternak #include <linux/platform_data/mlxreg.h>
14d00f779eSVadim Pasternak #include <linux/platform_device.h>
15d00f779eSVadim Pasternak #include <linux/regmap.h>
16d00f779eSVadim Pasternak
17d00f779eSVadim Pasternak /* I2C bus IO offsets */
18d00f779eSVadim Pasternak #define MLXREG_DPU_REG_FPGA1_VER_OFFSET 0x2400
19d00f779eSVadim Pasternak #define MLXREG_DPU_REG_FPGA1_PN_OFFSET 0x2404
20d00f779eSVadim Pasternak #define MLXREG_DPU_REG_FPGA1_PN1_OFFSET 0x2405
21d00f779eSVadim Pasternak #define MLXREG_DPU_REG_PG_OFFSET 0x2414
22d00f779eSVadim Pasternak #define MLXREG_DPU_REG_PG_EVENT_OFFSET 0x2415
23d00f779eSVadim Pasternak #define MLXREG_DPU_REG_PG_MASK_OFFSET 0x2416
24d00f779eSVadim Pasternak #define MLXREG_DPU_REG_RESET_GP1_OFFSET 0x2417
25d00f779eSVadim Pasternak #define MLXREG_DPU_REG_RST_CAUSE1_OFFSET 0x241e
26d00f779eSVadim Pasternak #define MLXREG_DPU_REG_GP0_RO_OFFSET 0x242b
27d00f779eSVadim Pasternak #define MLXREG_DPU_REG_GP0_OFFSET 0x242e
28d00f779eSVadim Pasternak #define MLXREG_DPU_REG_GP1_OFFSET 0x242c
29d00f779eSVadim Pasternak #define MLXREG_DPU_REG_GP4_OFFSET 0x2438
30d00f779eSVadim Pasternak #define MLXREG_DPU_REG_AGGRCO_OFFSET 0x2442
31d00f779eSVadim Pasternak #define MLXREG_DPU_REG_AGGRCO_MASK_OFFSET 0x2443
32d00f779eSVadim Pasternak #define MLXREG_DPU_REG_HEALTH_OFFSET 0x244d
33d00f779eSVadim Pasternak #define MLXREG_DPU_REG_HEALTH_EVENT_OFFSET 0x244e
34d00f779eSVadim Pasternak #define MLXREG_DPU_REG_HEALTH_MASK_OFFSET 0x244f
35d00f779eSVadim Pasternak #define MLXREG_DPU_REG_FPGA1_MVER_OFFSET 0x24de
36d00f779eSVadim Pasternak #define MLXREG_DPU_REG_CONFIG3_OFFSET 0x24fd
37d00f779eSVadim Pasternak #define MLXREG_DPU_REG_MAX 0x3fff
38d00f779eSVadim Pasternak
39d00f779eSVadim Pasternak /* Power Good event masks. */
40d00f779eSVadim Pasternak #define MLXREG_DPU_PG_VDDIO_MASK BIT(0)
41d00f779eSVadim Pasternak #define MLXREG_DPU_PG_VDD_CPU_MASK BIT(1)
42d00f779eSVadim Pasternak #define MLXREG_DPU_PG_VDD_MASK BIT(2)
43d00f779eSVadim Pasternak #define MLXREG_DPU_PG_1V8_MASK BIT(3)
44d00f779eSVadim Pasternak #define MLXREG_DPU_PG_COMPARATOR_MASK BIT(4)
45d00f779eSVadim Pasternak #define MLXREG_DPU_PG_VDDQ_MASK BIT(5)
46d00f779eSVadim Pasternak #define MLXREG_DPU_PG_HVDD_MASK BIT(6)
47d00f779eSVadim Pasternak #define MLXREG_DPU_PG_DVDD_MASK BIT(7)
48d00f779eSVadim Pasternak #define MLXREG_DPU_PG_MASK (MLXREG_DPU_PG_DVDD_MASK | \
49d00f779eSVadim Pasternak MLXREG_DPU_PG_HVDD_MASK | \
50d00f779eSVadim Pasternak MLXREG_DPU_PG_VDDQ_MASK | \
51d00f779eSVadim Pasternak MLXREG_DPU_PG_COMPARATOR_MASK | \
52d00f779eSVadim Pasternak MLXREG_DPU_PG_1V8_MASK | \
53d00f779eSVadim Pasternak MLXREG_DPU_PG_VDD_CPU_MASK | \
54d00f779eSVadim Pasternak MLXREG_DPU_PG_VDD_MASK | \
55d00f779eSVadim Pasternak MLXREG_DPU_PG_VDDIO_MASK)
56d00f779eSVadim Pasternak
57d00f779eSVadim Pasternak /* Health event masks. */
58d00f779eSVadim Pasternak #define MLXREG_DPU_HLTH_THERMAL_TRIP_MASK BIT(0)
59d00f779eSVadim Pasternak #define MLXREG_DPU_HLTH_UFM_UPGRADE_DONE_MASK BIT(1)
60d00f779eSVadim Pasternak #define MLXREG_DPU_HLTH_VDDQ_HOT_ALERT_MASK BIT(2)
61d00f779eSVadim Pasternak #define MLXREG_DPU_HLTH_VDD_CPU_HOT_ALERT_MASK BIT(3)
62d00f779eSVadim Pasternak #define MLXREG_DPU_HLTH_VDDQ_ALERT_MASK BIT(4)
63d00f779eSVadim Pasternak #define MLXREG_DPU_HLTH_VDD_CPU_ALERT_MASK BIT(5)
64d00f779eSVadim Pasternak #define MLXREG_DPU_HEALTH_MASK (MLXREG_DPU_HLTH_UFM_UPGRADE_DONE_MASK | \
65d00f779eSVadim Pasternak MLXREG_DPU_HLTH_VDDQ_HOT_ALERT_MASK | \
66d00f779eSVadim Pasternak MLXREG_DPU_HLTH_VDD_CPU_HOT_ALERT_MASK | \
67d00f779eSVadim Pasternak MLXREG_DPU_HLTH_VDDQ_ALERT_MASK | \
68d00f779eSVadim Pasternak MLXREG_DPU_HLTH_VDD_CPU_ALERT_MASK | \
69d00f779eSVadim Pasternak MLXREG_DPU_HLTH_THERMAL_TRIP_MASK)
70d00f779eSVadim Pasternak
71d00f779eSVadim Pasternak /* Hotplug aggregation masks. */
72d00f779eSVadim Pasternak #define MLXREG_DPU_HEALTH_AGGR_MASK BIT(0)
73d00f779eSVadim Pasternak #define MLXREG_DPU_PG_AGGR_MASK BIT(1)
74d00f779eSVadim Pasternak #define MLXREG_DPU_AGGR_MASK (MLXREG_DPU_HEALTH_AGGR_MASK | \
75d00f779eSVadim Pasternak MLXREG_DPU_PG_AGGR_MASK)
76d00f779eSVadim Pasternak
77d00f779eSVadim Pasternak /* Voltage regulator firmware update status mask. */
78d00f779eSVadim Pasternak #define MLXREG_DPU_VOLTREG_UPD_MASK GENMASK(5, 4)
79d00f779eSVadim Pasternak
80d00f779eSVadim Pasternak #define MLXREG_DPU_NR_NONE (-1)
81d00f779eSVadim Pasternak
82d00f779eSVadim Pasternak /*
83d00f779eSVadim Pasternak * enum mlxreg_dpu_type - Data Processor Unit types
84d00f779eSVadim Pasternak *
85d00f779eSVadim Pasternak * @MLXREG_DPU_BF3: DPU equipped with BF3 SoC;
86d00f779eSVadim Pasternak */
87d00f779eSVadim Pasternak enum mlxreg_dpu_type {
88d00f779eSVadim Pasternak MLXREG_DPU_BF3 = 0x0050,
89d00f779eSVadim Pasternak };
90d00f779eSVadim Pasternak
91d00f779eSVadim Pasternak /* Default register access data. */
92d00f779eSVadim Pasternak static struct mlxreg_core_data mlxreg_dpu_io_data[] = {
93d00f779eSVadim Pasternak {
94d00f779eSVadim Pasternak .label = "fpga1_version",
95d00f779eSVadim Pasternak .reg = MLXREG_DPU_REG_FPGA1_VER_OFFSET,
96d00f779eSVadim Pasternak .bit = GENMASK(7, 0),
97d00f779eSVadim Pasternak .mode = 0444,
98d00f779eSVadim Pasternak },
99d00f779eSVadim Pasternak {
100d00f779eSVadim Pasternak .label = "fpga1_pn",
101d00f779eSVadim Pasternak .reg = MLXREG_DPU_REG_FPGA1_PN_OFFSET,
102d00f779eSVadim Pasternak .bit = GENMASK(15, 0),
103d00f779eSVadim Pasternak .mode = 0444,
104d00f779eSVadim Pasternak .regnum = 2,
105d00f779eSVadim Pasternak },
106d00f779eSVadim Pasternak {
107d00f779eSVadim Pasternak .label = "fpga1_version_min",
108d00f779eSVadim Pasternak .reg = MLXREG_DPU_REG_FPGA1_MVER_OFFSET,
109d00f779eSVadim Pasternak .bit = GENMASK(7, 0),
110d00f779eSVadim Pasternak .mode = 0444,
111d00f779eSVadim Pasternak },
112d00f779eSVadim Pasternak {
113d00f779eSVadim Pasternak .label = "perst_rst",
114d00f779eSVadim Pasternak .reg = MLXREG_DPU_REG_RESET_GP1_OFFSET,
115d00f779eSVadim Pasternak .mask = GENMASK(7, 0) & ~BIT(0),
116d00f779eSVadim Pasternak .mode = 0644,
117d00f779eSVadim Pasternak },
118d00f779eSVadim Pasternak {
119d00f779eSVadim Pasternak .label = "usbphy_rst",
120d00f779eSVadim Pasternak .reg = MLXREG_DPU_REG_RESET_GP1_OFFSET,
121d00f779eSVadim Pasternak .mask = GENMASK(7, 0) & ~BIT(1),
122d00f779eSVadim Pasternak .mode = 0644,
123d00f779eSVadim Pasternak },
124d00f779eSVadim Pasternak {
125d00f779eSVadim Pasternak .label = "phy_rst",
126d00f779eSVadim Pasternak .reg = MLXREG_DPU_REG_RESET_GP1_OFFSET,
127d00f779eSVadim Pasternak .mask = GENMASK(7, 0) & ~BIT(2),
128d00f779eSVadim Pasternak .mode = 0644,
129d00f779eSVadim Pasternak },
130d00f779eSVadim Pasternak {
131d00f779eSVadim Pasternak .label = "tpm_rst",
132d00f779eSVadim Pasternak .reg = MLXREG_DPU_REG_RESET_GP1_OFFSET,
133d00f779eSVadim Pasternak .mask = GENMASK(7, 0) & ~BIT(6),
134d00f779eSVadim Pasternak .mode = 0644,
135d00f779eSVadim Pasternak },
136d00f779eSVadim Pasternak {
137d00f779eSVadim Pasternak .label = "reset_from_main_board",
138d00f779eSVadim Pasternak .reg = MLXREG_DPU_REG_RST_CAUSE1_OFFSET,
139d00f779eSVadim Pasternak .mask = GENMASK(7, 0) & ~BIT(1),
140d00f779eSVadim Pasternak .mode = 0444,
141d00f779eSVadim Pasternak },
142d00f779eSVadim Pasternak {
143d00f779eSVadim Pasternak .label = "reset_aux_pwr_or_reload",
144d00f779eSVadim Pasternak .reg = MLXREG_DPU_REG_RST_CAUSE1_OFFSET,
145d00f779eSVadim Pasternak .mask = GENMASK(7, 0) & ~BIT(2),
146d00f779eSVadim Pasternak .mode = 0444,
147d00f779eSVadim Pasternak },
148d00f779eSVadim Pasternak {
149d00f779eSVadim Pasternak .label = "reset_comex_pwr_fail",
150d00f779eSVadim Pasternak .reg = MLXREG_DPU_REG_RST_CAUSE1_OFFSET,
151d00f779eSVadim Pasternak .mask = GENMASK(7, 0) & ~BIT(3),
152d00f779eSVadim Pasternak .mode = 0444,
153d00f779eSVadim Pasternak },
154d00f779eSVadim Pasternak {
155d00f779eSVadim Pasternak .label = "reset_dpu_thermal",
156d00f779eSVadim Pasternak .reg = MLXREG_DPU_REG_RST_CAUSE1_OFFSET,
157d00f779eSVadim Pasternak .mask = GENMASK(7, 0) & ~BIT(6),
158d00f779eSVadim Pasternak .mode = 0444,
159d00f779eSVadim Pasternak },
160d00f779eSVadim Pasternak {
161d00f779eSVadim Pasternak .label = "reset_pwr_off",
162d00f779eSVadim Pasternak .reg = MLXREG_DPU_REG_RST_CAUSE1_OFFSET,
163d00f779eSVadim Pasternak .mask = GENMASK(7, 0) & ~BIT(7),
164d00f779eSVadim Pasternak .mode = 0444,
165d00f779eSVadim Pasternak },
166d00f779eSVadim Pasternak {
167d00f779eSVadim Pasternak .label = "dpu_id",
168d00f779eSVadim Pasternak .reg = MLXREG_DPU_REG_GP0_RO_OFFSET,
169d00f779eSVadim Pasternak .bit = GENMASK(3, 0),
170d00f779eSVadim Pasternak .mode = 0444,
171d00f779eSVadim Pasternak },
172d00f779eSVadim Pasternak {
173d00f779eSVadim Pasternak .label = "voltreg_update_status",
174d00f779eSVadim Pasternak .reg = MLXREG_DPU_REG_GP0_RO_OFFSET,
175d00f779eSVadim Pasternak .mask = MLXREG_DPU_VOLTREG_UPD_MASK,
176d00f779eSVadim Pasternak .bit = 5,
177d00f779eSVadim Pasternak .mode = 0444,
178d00f779eSVadim Pasternak },
179d00f779eSVadim Pasternak {
180d00f779eSVadim Pasternak .label = "boot_progress",
181d00f779eSVadim Pasternak .reg = MLXREG_DPU_REG_GP1_OFFSET,
182d00f779eSVadim Pasternak .mask = GENMASK(3, 0),
183d00f779eSVadim Pasternak .mode = 0444,
184d00f779eSVadim Pasternak },
185d00f779eSVadim Pasternak {
186d00f779eSVadim Pasternak .label = "ufm_upgrade",
187d00f779eSVadim Pasternak .reg = MLXREG_DPU_REG_GP4_OFFSET,
188d00f779eSVadim Pasternak .mask = GENMASK(7, 0) & ~BIT(1),
189d00f779eSVadim Pasternak .mode = 0644,
190d00f779eSVadim Pasternak },
191d00f779eSVadim Pasternak };
192d00f779eSVadim Pasternak
193d00f779eSVadim Pasternak static struct mlxreg_core_platform_data mlxreg_dpu_default_regs_io_data = {
194d00f779eSVadim Pasternak .data = mlxreg_dpu_io_data,
195d00f779eSVadim Pasternak .counter = ARRAY_SIZE(mlxreg_dpu_io_data),
196d00f779eSVadim Pasternak };
197d00f779eSVadim Pasternak
198d00f779eSVadim Pasternak /* Default hotplug data. */
199d00f779eSVadim Pasternak static struct mlxreg_core_data mlxreg_dpu_power_events_items_data[] = {
200d00f779eSVadim Pasternak {
201d00f779eSVadim Pasternak .label = "pg_vddio",
202d00f779eSVadim Pasternak .reg = MLXREG_DPU_REG_PG_OFFSET,
203d00f779eSVadim Pasternak .mask = MLXREG_DPU_PG_VDDIO_MASK,
204d00f779eSVadim Pasternak .hpdev.nr = MLXREG_DPU_NR_NONE,
205d00f779eSVadim Pasternak },
206d00f779eSVadim Pasternak {
207d00f779eSVadim Pasternak .label = "pg_vdd_cpu",
208d00f779eSVadim Pasternak .reg = MLXREG_DPU_REG_PG_OFFSET,
209d00f779eSVadim Pasternak .mask = MLXREG_DPU_PG_VDD_CPU_MASK,
210d00f779eSVadim Pasternak .hpdev.nr = MLXREG_DPU_NR_NONE,
211d00f779eSVadim Pasternak },
212d00f779eSVadim Pasternak {
213d00f779eSVadim Pasternak .label = "pg_vdd",
214d00f779eSVadim Pasternak .reg = MLXREG_DPU_REG_PG_OFFSET,
215d00f779eSVadim Pasternak .mask = MLXREG_DPU_PG_VDD_MASK,
216d00f779eSVadim Pasternak .hpdev.nr = MLXREG_DPU_NR_NONE,
217d00f779eSVadim Pasternak },
218d00f779eSVadim Pasternak {
219d00f779eSVadim Pasternak .label = "pg_1v8",
220d00f779eSVadim Pasternak .reg = MLXREG_DPU_REG_PG_OFFSET,
221d00f779eSVadim Pasternak .mask = MLXREG_DPU_PG_1V8_MASK,
222d00f779eSVadim Pasternak .hpdev.nr = MLXREG_DPU_NR_NONE,
223d00f779eSVadim Pasternak },
224d00f779eSVadim Pasternak {
225d00f779eSVadim Pasternak .label = "pg_comparator",
226d00f779eSVadim Pasternak .reg = MLXREG_DPU_REG_PG_OFFSET,
227d00f779eSVadim Pasternak .mask = MLXREG_DPU_PG_COMPARATOR_MASK,
228d00f779eSVadim Pasternak .hpdev.nr = MLXREG_DPU_NR_NONE,
229d00f779eSVadim Pasternak },
230d00f779eSVadim Pasternak {
231d00f779eSVadim Pasternak .label = "pg_vddq",
232d00f779eSVadim Pasternak .reg = MLXREG_DPU_REG_PG_OFFSET,
233d00f779eSVadim Pasternak .mask = MLXREG_DPU_PG_VDDQ_MASK,
234d00f779eSVadim Pasternak .hpdev.nr = MLXREG_DPU_NR_NONE,
235d00f779eSVadim Pasternak },
236d00f779eSVadim Pasternak {
237d00f779eSVadim Pasternak .label = "pg_hvdd",
238d00f779eSVadim Pasternak .reg = MLXREG_DPU_REG_PG_OFFSET,
239d00f779eSVadim Pasternak .mask = MLXREG_DPU_PG_HVDD_MASK,
240d00f779eSVadim Pasternak .hpdev.nr = MLXREG_DPU_NR_NONE,
241d00f779eSVadim Pasternak },
242d00f779eSVadim Pasternak {
243d00f779eSVadim Pasternak .label = "pg_dvdd",
244d00f779eSVadim Pasternak .reg = MLXREG_DPU_REG_PG_OFFSET,
245d00f779eSVadim Pasternak .mask = MLXREG_DPU_PG_DVDD_MASK,
246d00f779eSVadim Pasternak .hpdev.nr = MLXREG_DPU_NR_NONE,
247d00f779eSVadim Pasternak },
248d00f779eSVadim Pasternak };
249d00f779eSVadim Pasternak
250d00f779eSVadim Pasternak static struct mlxreg_core_data mlxreg_dpu_health_events_items_data[] = {
251d00f779eSVadim Pasternak {
252d00f779eSVadim Pasternak .label = "thermal_trip",
253d00f779eSVadim Pasternak .reg = MLXREG_DPU_REG_HEALTH_OFFSET,
254d00f779eSVadim Pasternak .mask = MLXREG_DPU_HLTH_THERMAL_TRIP_MASK,
255d00f779eSVadim Pasternak .hpdev.nr = MLXREG_DPU_NR_NONE,
256d00f779eSVadim Pasternak },
257d00f779eSVadim Pasternak {
258d00f779eSVadim Pasternak .label = "ufm_upgrade_done",
259d00f779eSVadim Pasternak .reg = MLXREG_DPU_REG_HEALTH_OFFSET,
260d00f779eSVadim Pasternak .mask = MLXREG_DPU_HLTH_UFM_UPGRADE_DONE_MASK,
261d00f779eSVadim Pasternak .hpdev.nr = MLXREG_DPU_NR_NONE,
262d00f779eSVadim Pasternak },
263d00f779eSVadim Pasternak {
264d00f779eSVadim Pasternak .label = "vddq_hot_alert",
265d00f779eSVadim Pasternak .reg = MLXREG_DPU_REG_HEALTH_OFFSET,
266d00f779eSVadim Pasternak .mask = MLXREG_DPU_HLTH_VDDQ_HOT_ALERT_MASK,
267d00f779eSVadim Pasternak .hpdev.nr = MLXREG_DPU_NR_NONE,
268d00f779eSVadim Pasternak },
269d00f779eSVadim Pasternak {
270d00f779eSVadim Pasternak .label = "vdd_cpu_hot_alert",
271d00f779eSVadim Pasternak .reg = MLXREG_DPU_REG_HEALTH_OFFSET,
272d00f779eSVadim Pasternak .mask = MLXREG_DPU_HLTH_VDD_CPU_HOT_ALERT_MASK,
273d00f779eSVadim Pasternak .hpdev.nr = MLXREG_DPU_NR_NONE,
274d00f779eSVadim Pasternak },
275d00f779eSVadim Pasternak {
276d00f779eSVadim Pasternak .label = "vddq_alert",
277d00f779eSVadim Pasternak .reg = MLXREG_DPU_REG_HEALTH_OFFSET,
278d00f779eSVadim Pasternak .mask = MLXREG_DPU_HLTH_VDDQ_ALERT_MASK,
279d00f779eSVadim Pasternak .hpdev.nr = MLXREG_DPU_NR_NONE,
280d00f779eSVadim Pasternak },
281d00f779eSVadim Pasternak {
282d00f779eSVadim Pasternak .label = "vdd_cpu_alert",
283d00f779eSVadim Pasternak .reg = MLXREG_DPU_REG_HEALTH_OFFSET,
284d00f779eSVadim Pasternak .mask = MLXREG_DPU_HLTH_VDD_CPU_ALERT_MASK,
285d00f779eSVadim Pasternak .hpdev.nr = MLXREG_DPU_NR_NONE,
286d00f779eSVadim Pasternak },
287d00f779eSVadim Pasternak };
288d00f779eSVadim Pasternak
289d00f779eSVadim Pasternak static struct mlxreg_core_item mlxreg_dpu_hotplug_items[] = {
290d00f779eSVadim Pasternak {
291d00f779eSVadim Pasternak .data = mlxreg_dpu_power_events_items_data,
292d00f779eSVadim Pasternak .aggr_mask = MLXREG_DPU_PG_AGGR_MASK,
293d00f779eSVadim Pasternak .reg = MLXREG_DPU_REG_PG_OFFSET,
294d00f779eSVadim Pasternak .mask = MLXREG_DPU_PG_MASK,
295d00f779eSVadim Pasternak .count = ARRAY_SIZE(mlxreg_dpu_power_events_items_data),
296d00f779eSVadim Pasternak .health = false,
297d00f779eSVadim Pasternak .inversed = 0,
298d00f779eSVadim Pasternak },
299d00f779eSVadim Pasternak {
300d00f779eSVadim Pasternak .data = mlxreg_dpu_health_events_items_data,
301d00f779eSVadim Pasternak .aggr_mask = MLXREG_DPU_HEALTH_AGGR_MASK,
302d00f779eSVadim Pasternak .reg = MLXREG_DPU_REG_HEALTH_OFFSET,
303d00f779eSVadim Pasternak .mask = MLXREG_DPU_HEALTH_MASK,
304d00f779eSVadim Pasternak .count = ARRAY_SIZE(mlxreg_dpu_health_events_items_data),
305d00f779eSVadim Pasternak .health = false,
306d00f779eSVadim Pasternak .inversed = 0,
307d00f779eSVadim Pasternak },
308d00f779eSVadim Pasternak };
309d00f779eSVadim Pasternak
310d00f779eSVadim Pasternak static
311d00f779eSVadim Pasternak struct mlxreg_core_hotplug_platform_data mlxreg_dpu_default_hotplug_data = {
312d00f779eSVadim Pasternak .items = mlxreg_dpu_hotplug_items,
313d00f779eSVadim Pasternak .count = ARRAY_SIZE(mlxreg_dpu_hotplug_items),
314d00f779eSVadim Pasternak .cell = MLXREG_DPU_REG_AGGRCO_OFFSET,
315d00f779eSVadim Pasternak .mask = MLXREG_DPU_AGGR_MASK,
316d00f779eSVadim Pasternak };
317d00f779eSVadim Pasternak
318d00f779eSVadim Pasternak /**
319d00f779eSVadim Pasternak * struct mlxreg_dpu - device private data
320d00f779eSVadim Pasternak * @dev: platform device
321d00f779eSVadim Pasternak * @data: platform core data
322d00f779eSVadim Pasternak * @io_data: register access platform data
323d00f779eSVadim Pasternak * @io_regs: register access device
324d00f779eSVadim Pasternak * @hotplug_data: hotplug platform data
325d00f779eSVadim Pasternak * @hotplug: hotplug device
326d00f779eSVadim Pasternak */
327d00f779eSVadim Pasternak struct mlxreg_dpu {
328d00f779eSVadim Pasternak struct device *dev;
329d00f779eSVadim Pasternak struct mlxreg_core_data *data;
330d00f779eSVadim Pasternak struct mlxreg_core_platform_data *io_data;
331d00f779eSVadim Pasternak struct platform_device *io_regs;
332d00f779eSVadim Pasternak struct mlxreg_core_hotplug_platform_data *hotplug_data;
333d00f779eSVadim Pasternak struct platform_device *hotplug;
334d00f779eSVadim Pasternak };
335d00f779eSVadim Pasternak
mlxreg_dpu_writeable_reg(struct device * dev,unsigned int reg)336d00f779eSVadim Pasternak static bool mlxreg_dpu_writeable_reg(struct device *dev, unsigned int reg)
337d00f779eSVadim Pasternak {
338d00f779eSVadim Pasternak switch (reg) {
339d00f779eSVadim Pasternak case MLXREG_DPU_REG_PG_EVENT_OFFSET:
340d00f779eSVadim Pasternak case MLXREG_DPU_REG_PG_MASK_OFFSET:
341d00f779eSVadim Pasternak case MLXREG_DPU_REG_RESET_GP1_OFFSET:
342d00f779eSVadim Pasternak case MLXREG_DPU_REG_GP0_OFFSET:
343d00f779eSVadim Pasternak case MLXREG_DPU_REG_GP1_OFFSET:
344d00f779eSVadim Pasternak case MLXREG_DPU_REG_GP4_OFFSET:
345d00f779eSVadim Pasternak case MLXREG_DPU_REG_AGGRCO_OFFSET:
346d00f779eSVadim Pasternak case MLXREG_DPU_REG_AGGRCO_MASK_OFFSET:
347d00f779eSVadim Pasternak case MLXREG_DPU_REG_HEALTH_EVENT_OFFSET:
348d00f779eSVadim Pasternak case MLXREG_DPU_REG_HEALTH_MASK_OFFSET:
349d00f779eSVadim Pasternak return true;
350d00f779eSVadim Pasternak }
351d00f779eSVadim Pasternak return false;
352d00f779eSVadim Pasternak }
353d00f779eSVadim Pasternak
mlxreg_dpu_readable_reg(struct device * dev,unsigned int reg)354d00f779eSVadim Pasternak static bool mlxreg_dpu_readable_reg(struct device *dev, unsigned int reg)
355d00f779eSVadim Pasternak {
356d00f779eSVadim Pasternak switch (reg) {
357d00f779eSVadim Pasternak case MLXREG_DPU_REG_FPGA1_VER_OFFSET:
358d00f779eSVadim Pasternak case MLXREG_DPU_REG_FPGA1_PN_OFFSET:
359d00f779eSVadim Pasternak case MLXREG_DPU_REG_FPGA1_PN1_OFFSET:
360d00f779eSVadim Pasternak case MLXREG_DPU_REG_PG_OFFSET:
361d00f779eSVadim Pasternak case MLXREG_DPU_REG_PG_EVENT_OFFSET:
362d00f779eSVadim Pasternak case MLXREG_DPU_REG_PG_MASK_OFFSET:
363d00f779eSVadim Pasternak case MLXREG_DPU_REG_RESET_GP1_OFFSET:
364d00f779eSVadim Pasternak case MLXREG_DPU_REG_RST_CAUSE1_OFFSET:
365d00f779eSVadim Pasternak case MLXREG_DPU_REG_GP0_RO_OFFSET:
366d00f779eSVadim Pasternak case MLXREG_DPU_REG_GP0_OFFSET:
367d00f779eSVadim Pasternak case MLXREG_DPU_REG_GP1_OFFSET:
368d00f779eSVadim Pasternak case MLXREG_DPU_REG_GP4_OFFSET:
369d00f779eSVadim Pasternak case MLXREG_DPU_REG_AGGRCO_OFFSET:
370d00f779eSVadim Pasternak case MLXREG_DPU_REG_AGGRCO_MASK_OFFSET:
371d00f779eSVadim Pasternak case MLXREG_DPU_REG_HEALTH_OFFSET:
372d00f779eSVadim Pasternak case MLXREG_DPU_REG_HEALTH_EVENT_OFFSET:
373d00f779eSVadim Pasternak case MLXREG_DPU_REG_HEALTH_MASK_OFFSET:
374d00f779eSVadim Pasternak case MLXREG_DPU_REG_FPGA1_MVER_OFFSET:
375d00f779eSVadim Pasternak case MLXREG_DPU_REG_CONFIG3_OFFSET:
376d00f779eSVadim Pasternak return true;
377d00f779eSVadim Pasternak }
378d00f779eSVadim Pasternak return false;
379d00f779eSVadim Pasternak }
380d00f779eSVadim Pasternak
mlxreg_dpu_volatile_reg(struct device * dev,unsigned int reg)381d00f779eSVadim Pasternak static bool mlxreg_dpu_volatile_reg(struct device *dev, unsigned int reg)
382d00f779eSVadim Pasternak {
383d00f779eSVadim Pasternak switch (reg) {
384d00f779eSVadim Pasternak case MLXREG_DPU_REG_FPGA1_VER_OFFSET:
385d00f779eSVadim Pasternak case MLXREG_DPU_REG_FPGA1_PN_OFFSET:
386d00f779eSVadim Pasternak case MLXREG_DPU_REG_FPGA1_PN1_OFFSET:
387d00f779eSVadim Pasternak case MLXREG_DPU_REG_PG_OFFSET:
388d00f779eSVadim Pasternak case MLXREG_DPU_REG_PG_EVENT_OFFSET:
389d00f779eSVadim Pasternak case MLXREG_DPU_REG_PG_MASK_OFFSET:
390d00f779eSVadim Pasternak case MLXREG_DPU_REG_RESET_GP1_OFFSET:
391d00f779eSVadim Pasternak case MLXREG_DPU_REG_RST_CAUSE1_OFFSET:
392d00f779eSVadim Pasternak case MLXREG_DPU_REG_GP0_RO_OFFSET:
393d00f779eSVadim Pasternak case MLXREG_DPU_REG_GP0_OFFSET:
394d00f779eSVadim Pasternak case MLXREG_DPU_REG_GP1_OFFSET:
395d00f779eSVadim Pasternak case MLXREG_DPU_REG_GP4_OFFSET:
396d00f779eSVadim Pasternak case MLXREG_DPU_REG_AGGRCO_OFFSET:
397d00f779eSVadim Pasternak case MLXREG_DPU_REG_AGGRCO_MASK_OFFSET:
398d00f779eSVadim Pasternak case MLXREG_DPU_REG_HEALTH_OFFSET:
399d00f779eSVadim Pasternak case MLXREG_DPU_REG_HEALTH_EVENT_OFFSET:
400d00f779eSVadim Pasternak case MLXREG_DPU_REG_HEALTH_MASK_OFFSET:
401d00f779eSVadim Pasternak case MLXREG_DPU_REG_FPGA1_MVER_OFFSET:
402d00f779eSVadim Pasternak case MLXREG_DPU_REG_CONFIG3_OFFSET:
403d00f779eSVadim Pasternak return true;
404d00f779eSVadim Pasternak }
405d00f779eSVadim Pasternak return false;
406d00f779eSVadim Pasternak }
407d00f779eSVadim Pasternak
408d00f779eSVadim Pasternak /* Configuration for the register map of a device with 2 bytes address space. */
409d00f779eSVadim Pasternak static const struct regmap_config mlxreg_dpu_regmap_conf = {
410d00f779eSVadim Pasternak .reg_bits = 16,
411d00f779eSVadim Pasternak .val_bits = 8,
412d00f779eSVadim Pasternak .max_register = MLXREG_DPU_REG_MAX,
413d00f779eSVadim Pasternak .cache_type = REGCACHE_FLAT,
414d00f779eSVadim Pasternak .writeable_reg = mlxreg_dpu_writeable_reg,
415d00f779eSVadim Pasternak .readable_reg = mlxreg_dpu_readable_reg,
416d00f779eSVadim Pasternak .volatile_reg = mlxreg_dpu_volatile_reg,
417d00f779eSVadim Pasternak };
418d00f779eSVadim Pasternak
419d00f779eSVadim Pasternak static int
mlxreg_dpu_copy_hotplug_data(struct device * dev,struct mlxreg_dpu * mlxreg_dpu,const struct mlxreg_core_hotplug_platform_data * hotplug_data)420d00f779eSVadim Pasternak mlxreg_dpu_copy_hotplug_data(struct device *dev, struct mlxreg_dpu *mlxreg_dpu,
421d00f779eSVadim Pasternak const struct mlxreg_core_hotplug_platform_data *hotplug_data)
422d00f779eSVadim Pasternak {
423d00f779eSVadim Pasternak struct mlxreg_core_item *item;
424d00f779eSVadim Pasternak int i;
425d00f779eSVadim Pasternak
426d00f779eSVadim Pasternak mlxreg_dpu->hotplug_data = devm_kmemdup(dev, hotplug_data,
427d00f779eSVadim Pasternak sizeof(*mlxreg_dpu->hotplug_data), GFP_KERNEL);
428d00f779eSVadim Pasternak if (!mlxreg_dpu->hotplug_data)
429d00f779eSVadim Pasternak return -ENOMEM;
430d00f779eSVadim Pasternak
431d00f779eSVadim Pasternak mlxreg_dpu->hotplug_data->items = devm_kmemdup(dev, hotplug_data->items,
432d00f779eSVadim Pasternak mlxreg_dpu->hotplug_data->count *
433d00f779eSVadim Pasternak sizeof(*mlxreg_dpu->hotplug_data->items),
434d00f779eSVadim Pasternak GFP_KERNEL);
435d00f779eSVadim Pasternak if (!mlxreg_dpu->hotplug_data->items)
436d00f779eSVadim Pasternak return -ENOMEM;
437d00f779eSVadim Pasternak
438d00f779eSVadim Pasternak item = mlxreg_dpu->hotplug_data->items;
439d00f779eSVadim Pasternak for (i = 0; i < hotplug_data->count; i++, item++) {
440d00f779eSVadim Pasternak item->data = devm_kmemdup(dev, hotplug_data->items[i].data,
441d00f779eSVadim Pasternak hotplug_data->items[i].count * sizeof(*item->data),
442d00f779eSVadim Pasternak GFP_KERNEL);
443d00f779eSVadim Pasternak if (!item->data)
444d00f779eSVadim Pasternak return -ENOMEM;
445d00f779eSVadim Pasternak }
446d00f779eSVadim Pasternak
447d00f779eSVadim Pasternak return 0;
448d00f779eSVadim Pasternak }
449d00f779eSVadim Pasternak
mlxreg_dpu_config_init(struct mlxreg_dpu * mlxreg_dpu,void * regmap,struct mlxreg_core_data * data,int irq)450d00f779eSVadim Pasternak static int mlxreg_dpu_config_init(struct mlxreg_dpu *mlxreg_dpu, void *regmap,
451d00f779eSVadim Pasternak struct mlxreg_core_data *data, int irq)
452d00f779eSVadim Pasternak {
453d00f779eSVadim Pasternak struct device *dev = &data->hpdev.client->dev;
454d00f779eSVadim Pasternak u32 regval;
455d00f779eSVadim Pasternak int err;
456d00f779eSVadim Pasternak
457d00f779eSVadim Pasternak /* Validate DPU type. */
458d00f779eSVadim Pasternak err = regmap_read(regmap, MLXREG_DPU_REG_CONFIG3_OFFSET, ®val);
459d00f779eSVadim Pasternak if (err)
460d00f779eSVadim Pasternak return err;
461d00f779eSVadim Pasternak
462d00f779eSVadim Pasternak switch (regval) {
463d00f779eSVadim Pasternak case MLXREG_DPU_BF3:
464d00f779eSVadim Pasternak /* Copy platform specific hotplug data. */
465d00f779eSVadim Pasternak err = mlxreg_dpu_copy_hotplug_data(dev, mlxreg_dpu,
466d00f779eSVadim Pasternak &mlxreg_dpu_default_hotplug_data);
467d00f779eSVadim Pasternak if (err)
468d00f779eSVadim Pasternak return err;
469d00f779eSVadim Pasternak
470d00f779eSVadim Pasternak mlxreg_dpu->io_data = &mlxreg_dpu_default_regs_io_data;
471d00f779eSVadim Pasternak
472d00f779eSVadim Pasternak break;
473d00f779eSVadim Pasternak default:
474d00f779eSVadim Pasternak return -ENODEV;
475d00f779eSVadim Pasternak }
476d00f779eSVadim Pasternak
477d00f779eSVadim Pasternak /* Register IO access driver. */
478d00f779eSVadim Pasternak if (mlxreg_dpu->io_data) {
479d00f779eSVadim Pasternak mlxreg_dpu->io_data->regmap = regmap;
480d00f779eSVadim Pasternak mlxreg_dpu->io_regs =
481d00f779eSVadim Pasternak platform_device_register_resndata(dev, "mlxreg-io",
482d00f779eSVadim Pasternak data->slot, NULL, 0,
483d00f779eSVadim Pasternak mlxreg_dpu->io_data,
484d00f779eSVadim Pasternak sizeof(*mlxreg_dpu->io_data));
485d00f779eSVadim Pasternak if (IS_ERR(mlxreg_dpu->io_regs)) {
486d00f779eSVadim Pasternak dev_err(dev, "Failed to create regio for client %s at bus %d at addr 0x%02x\n",
487d00f779eSVadim Pasternak data->hpdev.brdinfo->type, data->hpdev.nr,
488d00f779eSVadim Pasternak data->hpdev.brdinfo->addr);
489d00f779eSVadim Pasternak return PTR_ERR(mlxreg_dpu->io_regs);
490d00f779eSVadim Pasternak }
491d00f779eSVadim Pasternak }
492d00f779eSVadim Pasternak
493d00f779eSVadim Pasternak /* Register hotplug driver. */
494d00f779eSVadim Pasternak if (mlxreg_dpu->hotplug_data && irq) {
495d00f779eSVadim Pasternak mlxreg_dpu->hotplug_data->regmap = regmap;
496d00f779eSVadim Pasternak mlxreg_dpu->hotplug_data->irq = irq;
497d00f779eSVadim Pasternak mlxreg_dpu->hotplug =
498d00f779eSVadim Pasternak platform_device_register_resndata(dev, "mlxreg-hotplug",
499d00f779eSVadim Pasternak data->slot, NULL, 0,
500d00f779eSVadim Pasternak mlxreg_dpu->hotplug_data,
501d00f779eSVadim Pasternak sizeof(*mlxreg_dpu->hotplug_data));
502d00f779eSVadim Pasternak if (IS_ERR(mlxreg_dpu->hotplug)) {
503d00f779eSVadim Pasternak err = PTR_ERR(mlxreg_dpu->hotplug);
504d00f779eSVadim Pasternak goto fail_register_hotplug;
505d00f779eSVadim Pasternak }
506d00f779eSVadim Pasternak }
507d00f779eSVadim Pasternak
508d00f779eSVadim Pasternak return 0;
509d00f779eSVadim Pasternak
510d00f779eSVadim Pasternak fail_register_hotplug:
511d00f779eSVadim Pasternak platform_device_unregister(mlxreg_dpu->io_regs);
512d00f779eSVadim Pasternak
513d00f779eSVadim Pasternak return err;
514d00f779eSVadim Pasternak }
515d00f779eSVadim Pasternak
mlxreg_dpu_config_exit(struct mlxreg_dpu * mlxreg_dpu)516d00f779eSVadim Pasternak static void mlxreg_dpu_config_exit(struct mlxreg_dpu *mlxreg_dpu)
517d00f779eSVadim Pasternak {
518d00f779eSVadim Pasternak platform_device_unregister(mlxreg_dpu->hotplug);
519d00f779eSVadim Pasternak platform_device_unregister(mlxreg_dpu->io_regs);
520d00f779eSVadim Pasternak }
521d00f779eSVadim Pasternak
mlxreg_dpu_probe(struct platform_device * pdev)522d00f779eSVadim Pasternak static int mlxreg_dpu_probe(struct platform_device *pdev)
523d00f779eSVadim Pasternak {
524d00f779eSVadim Pasternak struct mlxreg_core_data *data;
525d00f779eSVadim Pasternak struct mlxreg_dpu *mlxreg_dpu;
526d00f779eSVadim Pasternak void *regmap;
527d00f779eSVadim Pasternak int err;
528d00f779eSVadim Pasternak
529d00f779eSVadim Pasternak data = dev_get_platdata(&pdev->dev);
530d00f779eSVadim Pasternak if (!data || !data->hpdev.brdinfo)
531d00f779eSVadim Pasternak return -EINVAL;
532d00f779eSVadim Pasternak
533d00f779eSVadim Pasternak data->hpdev.adapter = i2c_get_adapter(data->hpdev.nr);
534d00f779eSVadim Pasternak if (!data->hpdev.adapter)
535d00f779eSVadim Pasternak return -EPROBE_DEFER;
536d00f779eSVadim Pasternak
537d00f779eSVadim Pasternak mlxreg_dpu = devm_kzalloc(&pdev->dev, sizeof(*mlxreg_dpu), GFP_KERNEL);
538*f94ffc3fSVadim Pasternak if (!mlxreg_dpu) {
539*f94ffc3fSVadim Pasternak err = -ENOMEM;
540*f94ffc3fSVadim Pasternak goto alloc_fail;
541*f94ffc3fSVadim Pasternak }
542d00f779eSVadim Pasternak
543d00f779eSVadim Pasternak /* Create device at the top of DPU I2C tree. */
544d00f779eSVadim Pasternak data->hpdev.client = i2c_new_client_device(data->hpdev.adapter,
545d00f779eSVadim Pasternak data->hpdev.brdinfo);
546d00f779eSVadim Pasternak if (IS_ERR(data->hpdev.client)) {
547d00f779eSVadim Pasternak dev_err(&pdev->dev, "Failed to create client %s at bus %d at addr 0x%02x\n",
548d00f779eSVadim Pasternak data->hpdev.brdinfo->type, data->hpdev.nr, data->hpdev.brdinfo->addr);
549d00f779eSVadim Pasternak err = PTR_ERR(data->hpdev.client);
550d00f779eSVadim Pasternak goto i2c_new_device_fail;
551d00f779eSVadim Pasternak }
552d00f779eSVadim Pasternak
553d00f779eSVadim Pasternak regmap = devm_regmap_init_i2c(data->hpdev.client, &mlxreg_dpu_regmap_conf);
554d00f779eSVadim Pasternak if (IS_ERR(regmap)) {
555d00f779eSVadim Pasternak dev_err(&pdev->dev, "Failed to create regmap for client %s at bus %d at addr 0x%02x\n",
556d00f779eSVadim Pasternak data->hpdev.brdinfo->type, data->hpdev.nr, data->hpdev.brdinfo->addr);
557d00f779eSVadim Pasternak err = PTR_ERR(regmap);
558d00f779eSVadim Pasternak goto devm_regmap_init_i2c_fail;
559d00f779eSVadim Pasternak }
560d00f779eSVadim Pasternak
561d00f779eSVadim Pasternak /* Sync registers with hardware. */
562d00f779eSVadim Pasternak regcache_mark_dirty(regmap);
563d00f779eSVadim Pasternak err = regcache_sync(regmap);
564d00f779eSVadim Pasternak if (err) {
565d00f779eSVadim Pasternak dev_err(&pdev->dev, "Failed to sync regmap for client %s at bus %d at addr 0x%02x\n",
566d00f779eSVadim Pasternak data->hpdev.brdinfo->type, data->hpdev.nr, data->hpdev.brdinfo->addr);
567d00f779eSVadim Pasternak goto regcache_sync_fail;
568d00f779eSVadim Pasternak }
569d00f779eSVadim Pasternak
570d00f779eSVadim Pasternak mlxreg_dpu->data = data;
571d00f779eSVadim Pasternak mlxreg_dpu->dev = &pdev->dev;
572d00f779eSVadim Pasternak platform_set_drvdata(pdev, mlxreg_dpu);
573d00f779eSVadim Pasternak
574d00f779eSVadim Pasternak err = mlxreg_dpu_config_init(mlxreg_dpu, regmap, data, data->hpdev.brdinfo->irq);
575d00f779eSVadim Pasternak if (err)
576d00f779eSVadim Pasternak goto mlxreg_dpu_config_init_fail;
577d00f779eSVadim Pasternak
578d00f779eSVadim Pasternak return err;
579d00f779eSVadim Pasternak
580d00f779eSVadim Pasternak mlxreg_dpu_config_init_fail:
581d00f779eSVadim Pasternak regcache_sync_fail:
582d00f779eSVadim Pasternak devm_regmap_init_i2c_fail:
583d00f779eSVadim Pasternak i2c_unregister_device(data->hpdev.client);
584d00f779eSVadim Pasternak i2c_new_device_fail:
585*f94ffc3fSVadim Pasternak alloc_fail:
586d00f779eSVadim Pasternak i2c_put_adapter(data->hpdev.adapter);
587d00f779eSVadim Pasternak return err;
588d00f779eSVadim Pasternak }
589d00f779eSVadim Pasternak
mlxreg_dpu_remove(struct platform_device * pdev)590d00f779eSVadim Pasternak static void mlxreg_dpu_remove(struct platform_device *pdev)
591d00f779eSVadim Pasternak {
592d00f779eSVadim Pasternak struct mlxreg_core_data *data = dev_get_platdata(&pdev->dev);
593d00f779eSVadim Pasternak struct mlxreg_dpu *mlxreg_dpu = platform_get_drvdata(pdev);
594d00f779eSVadim Pasternak
595d00f779eSVadim Pasternak mlxreg_dpu_config_exit(mlxreg_dpu);
596d00f779eSVadim Pasternak i2c_unregister_device(data->hpdev.client);
597d00f779eSVadim Pasternak i2c_put_adapter(data->hpdev.adapter);
598d00f779eSVadim Pasternak }
599d00f779eSVadim Pasternak
600d00f779eSVadim Pasternak static struct platform_driver mlxreg_dpu_driver = {
601d00f779eSVadim Pasternak .probe = mlxreg_dpu_probe,
602d00f779eSVadim Pasternak .remove = mlxreg_dpu_remove,
603d00f779eSVadim Pasternak .driver = {
604d00f779eSVadim Pasternak .name = "mlxreg-dpu",
605d00f779eSVadim Pasternak },
606d00f779eSVadim Pasternak };
607d00f779eSVadim Pasternak
608d00f779eSVadim Pasternak module_platform_driver(mlxreg_dpu_driver);
609d00f779eSVadim Pasternak
610d00f779eSVadim Pasternak MODULE_AUTHOR("Vadim Pasternak <vadimp@nvidia.com>");
611d00f779eSVadim Pasternak MODULE_DESCRIPTION("Nvidia Data Processor Unit platform driver");
612d00f779eSVadim Pasternak MODULE_LICENSE("Dual BSD/GPL");
613d00f779eSVadim Pasternak MODULE_ALIAS("platform:mlxreg-dpu");
614