1 // SPDX-License-Identifier: GPL-2.0-or-later
3 * Copyright (C) 2020 Martin Blumenstingl <martin.blumenstingl@googlemail.com>
6 #include <linux/bitfield.h>
7 #include <linux/bitops.h>
9 #include <linux/delay.h>
10 #include <linux/genalloc.h>
12 #include <linux/mfd/syscon.h>
13 #include <linux/module.h>
14 #include <linux/platform_device.h>
15 #include <linux/property.h>
16 #include <linux/regmap.h>
17 #include <linux/remoteproc.h>
18 #include <linux/reset.h>
19 #include <linux/sizes.h>
21 #include "remoteproc_internal.h"
23 #define AO_REMAP_REG0 0x0
24 #define AO_REMAP_REG0_REMAP_AHB_SRAM_BITS_17_14_FOR_ARM_CPU GENMASK(3, 0)
26 #define AO_REMAP_REG1 0x4
27 #define AO_REMAP_REG1_MOVE_AHB_SRAM_TO_0X0_INSTEAD_OF_DDR BIT(4)
28 #define AO_REMAP_REG1_REMAP_AHB_SRAM_BITS_17_14_FOR_MEDIA_CPU GENMASK(3, 0)
30 #define AO_CPU_CNTL 0x0
31 #define AO_CPU_CNTL_AHB_SRAM_BITS_31_20 GENMASK(28, 16)
32 #define AO_CPU_CNTL_HALT BIT(9)
33 #define AO_CPU_CNTL_UNKNONWN BIT(8)
34 #define AO_CPU_CNTL_RUN BIT(0)
36 #define AO_CPU_STAT 0x4
38 #define AO_SECURE_REG0 0x0
39 #define AO_SECURE_REG0_AHB_SRAM_BITS_19_12 GENMASK(15, 8)
41 /* Only bits [31:20] and [17:14] are usable, all other bits must be zero */
42 #define MESON_AO_RPROC_SRAM_USABLE_BITS 0xfff3c000ULL
44 #define MESON_AO_RPROC_MEMORY_OFFSET 0x10000000
46 struct meson_mx_ao_arc_rproc_priv
{
47 void __iomem
*remap_base
;
48 void __iomem
*cpu_base
;
49 unsigned long sram_va
;
52 struct gen_pool
*sram_pool
;
53 struct reset_control
*arc_reset
;
55 struct regmap
*secbus2_regmap
;
58 static int meson_mx_ao_arc_rproc_start(struct rproc
*rproc
)
60 struct meson_mx_ao_arc_rproc_priv
*priv
= rproc
->priv
;
61 phys_addr_t translated_sram_addr
;
65 ret
= clk_prepare_enable(priv
->arc_pclk
);
69 tmp
= FIELD_PREP(AO_REMAP_REG0_REMAP_AHB_SRAM_BITS_17_14_FOR_ARM_CPU
,
71 writel(tmp
, priv
->remap_base
+ AO_REMAP_REG0
);
74 * The SRAM content as seen by the ARC core always starts at 0x0
75 * regardless of the value given here (this was discovered by trial and
76 * error). For SoCs older than Meson6 we probably have to set
77 * AO_REMAP_REG1_MOVE_AHB_SRAM_TO_0X0_INSTEAD_OF_DDR to achieve the
78 * same. (At least) For Meson8 and newer that bit must not be set.
80 writel(0x0, priv
->remap_base
+ AO_REMAP_REG1
);
82 regmap_update_bits(priv
->secbus2_regmap
, AO_SECURE_REG0
,
83 AO_SECURE_REG0_AHB_SRAM_BITS_19_12
,
84 FIELD_PREP(AO_SECURE_REG0_AHB_SRAM_BITS_19_12
,
85 priv
->sram_pa
>> 12));
87 ret
= reset_control_reset(priv
->arc_reset
);
89 clk_disable_unprepare(priv
->arc_pclk
);
93 usleep_range(10, 100);
96 * Convert from 0xd9000000 to 0xc9000000 as the vendor driver does.
97 * This only seems to be relevant for the AO_CPU_CNTL register. It is
98 * unknown why this is needed.
100 translated_sram_addr
= priv
->sram_pa
- MESON_AO_RPROC_MEMORY_OFFSET
;
102 tmp
= FIELD_PREP(AO_CPU_CNTL_AHB_SRAM_BITS_31_20
,
103 translated_sram_addr
>> 20);
104 tmp
|= AO_CPU_CNTL_UNKNONWN
| AO_CPU_CNTL_RUN
;
105 writel(tmp
, priv
->cpu_base
+ AO_CPU_CNTL
);
107 usleep_range(20, 200);
112 static int meson_mx_ao_arc_rproc_stop(struct rproc
*rproc
)
114 struct meson_mx_ao_arc_rproc_priv
*priv
= rproc
->priv
;
116 writel(AO_CPU_CNTL_HALT
, priv
->cpu_base
+ AO_CPU_CNTL
);
118 clk_disable_unprepare(priv
->arc_pclk
);
123 static void *meson_mx_ao_arc_rproc_da_to_va(struct rproc
*rproc
, u64 da
,
124 size_t len
, bool *is_iomem
)
126 struct meson_mx_ao_arc_rproc_priv
*priv
= rproc
->priv
;
128 /* The memory from the ARC core's perspective always starts at 0x0. */
129 if ((da
+ len
) > priv
->sram_size
)
132 return (void *)priv
->sram_va
+ da
;
135 static struct rproc_ops meson_mx_ao_arc_rproc_ops
= {
136 .start
= meson_mx_ao_arc_rproc_start
,
137 .stop
= meson_mx_ao_arc_rproc_stop
,
138 .da_to_va
= meson_mx_ao_arc_rproc_da_to_va
,
139 .get_boot_addr
= rproc_elf_get_boot_addr
,
140 .load
= rproc_elf_load_segments
,
141 .sanity_check
= rproc_elf_sanity_check
,
144 static int meson_mx_ao_arc_rproc_probe(struct platform_device
*pdev
)
146 struct meson_mx_ao_arc_rproc_priv
*priv
;
147 struct device
*dev
= &pdev
->dev
;
148 const char *fw_name
= NULL
;
152 device_property_read_string(dev
, "firmware-name", &fw_name
);
154 rproc
= devm_rproc_alloc(dev
, "meson-mx-ao-arc",
155 &meson_mx_ao_arc_rproc_ops
, fw_name
,
160 rproc
->has_iommu
= false;
163 priv
->sram_pool
= of_gen_pool_get(dev
->of_node
, "sram", 0);
164 if (!priv
->sram_pool
) {
165 dev_err(dev
, "Could not get SRAM pool\n");
169 priv
->sram_size
= gen_pool_avail(priv
->sram_pool
);
171 priv
->sram_va
= gen_pool_alloc(priv
->sram_pool
, priv
->sram_size
);
172 if (!priv
->sram_va
) {
173 dev_err(dev
, "Could not alloc memory in SRAM pool\n");
177 priv
->sram_pa
= gen_pool_virt_to_phys(priv
->sram_pool
, priv
->sram_va
);
178 if (priv
->sram_pa
& ~MESON_AO_RPROC_SRAM_USABLE_BITS
) {
179 dev_err(dev
, "SRAM address contains unusable bits\n");
181 goto err_free_genpool
;
184 priv
->secbus2_regmap
= syscon_regmap_lookup_by_phandle(dev
->of_node
,
186 if (IS_ERR(priv
->secbus2_regmap
)) {
187 dev_err(dev
, "Failed to find SECBUS2 regmap\n");
188 ret
= PTR_ERR(priv
->secbus2_regmap
);
189 goto err_free_genpool
;
192 priv
->remap_base
= devm_platform_ioremap_resource_byname(pdev
, "remap");
193 if (IS_ERR(priv
->remap_base
)) {
194 ret
= PTR_ERR(priv
->remap_base
);
195 goto err_free_genpool
;
198 priv
->cpu_base
= devm_platform_ioremap_resource_byname(pdev
, "cpu");
199 if (IS_ERR(priv
->cpu_base
)) {
200 ret
= PTR_ERR(priv
->cpu_base
);
201 goto err_free_genpool
;
204 priv
->arc_reset
= devm_reset_control_get_exclusive(dev
, NULL
);
205 if (IS_ERR(priv
->arc_reset
)) {
206 dev_err(dev
, "Failed to get ARC reset\n");
207 ret
= PTR_ERR(priv
->arc_reset
);
208 goto err_free_genpool
;
211 priv
->arc_pclk
= devm_clk_get(dev
, NULL
);
212 if (IS_ERR(priv
->arc_pclk
)) {
213 dev_err(dev
, "Failed to get the ARC PCLK\n");
214 ret
= PTR_ERR(priv
->arc_pclk
);
215 goto err_free_genpool
;
218 platform_set_drvdata(pdev
, rproc
);
220 ret
= rproc_add(rproc
);
222 goto err_free_genpool
;
227 gen_pool_free(priv
->sram_pool
, priv
->sram_va
, priv
->sram_size
);
231 static void meson_mx_ao_arc_rproc_remove(struct platform_device
*pdev
)
233 struct rproc
*rproc
= platform_get_drvdata(pdev
);
234 struct meson_mx_ao_arc_rproc_priv
*priv
= rproc
->priv
;
237 gen_pool_free(priv
->sram_pool
, priv
->sram_va
, priv
->sram_size
);
240 static const struct of_device_id meson_mx_ao_arc_rproc_match
[] = {
241 { .compatible
= "amlogic,meson8-ao-arc" },
242 { .compatible
= "amlogic,meson8b-ao-arc" },
245 MODULE_DEVICE_TABLE(of
, meson_mx_ao_arc_rproc_match
);
247 static struct platform_driver meson_mx_ao_arc_rproc_driver
= {
248 .probe
= meson_mx_ao_arc_rproc_probe
,
249 .remove
= meson_mx_ao_arc_rproc_remove
,
251 .name
= "meson-mx-ao-arc-rproc",
252 .of_match_table
= meson_mx_ao_arc_rproc_match
,
255 module_platform_driver(meson_mx_ao_arc_rproc_driver
);
257 MODULE_DESCRIPTION("Amlogic Meson6/8/8b/8m2 AO ARC remote processor driver");
258 MODULE_AUTHOR("Martin Blumenstingl <martin.blumenstingl@googlemail.com>");
259 MODULE_LICENSE("GPL v2");