xref: /rk3399_rockchip-uboot/drivers/cpu/rockchip_amp.c (revision cfcc706c901d603707657919484e4f65467be9ff)
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * Copyright (c) 2019 Fuzhou Rockchip Electronics Co., Ltd
4  */
5 #include <common.h>
6 #include <amp.h>
7 #include <boot_rkimg.h>
8 #include <bidram.h>
9 #include <dm.h>
10 #include <sysmem.h>
11 #include <asm/arch/rockchip_smccc.h>
12 
13 #define AMP_I(fmt, args...)	printf("AMP: "fmt, ##args)
14 #define AMP_E(fmt, args...)	printf("AMP Error: "fmt, ##args)
15 
16 /*
17  * An example for amps dts node configure:
18  *
19  * amps {
20  *	compatible = "uboot,rockchip-amp";
21  *	status = "okay";
22  *
23  *	amp@0 {
24  *		description  = "mcu-os1";
25  *		partition    = "mcu1";
26  *		cpu          = <0x1>;		// this is mpidr!
27  *		load         = <0x800000>;
28  *		entry        = <0x800000>;
29  *		memory       = <0x800000 0x400000>;
30  *	};
31  *
32  *	amp@1 {
33  *		......
34  *	};
35  *
36  *	......
37  * };
38  *
39  * U-Boot loads "mcu-os1" firmware to "0x800000" address from partiton
40  * "mcu1" for cpu[1], the cpu[1] entry address is 0x800000. And
41  * U-Boot reserve memory from 0x800000 with 0x400000 size in order
42  * to make it invisible for kernel.
43  *
44  * Please use rockchip tool "mkkrnlimg" to pack firmware binary, example:
45  * ./scripts/mkkrnlimg mcu-os1.bin mcu-os1.img
46  */
47 
48 static int rockchip_amp_cpu_on(struct udevice *dev)
49 {
50 	struct dm_amp_uclass_platdata *uc_pdata;
51 	struct blk_desc *dev_desc;
52 	disk_partition_t part_info;
53 	int ret, size;
54 
55 	uc_pdata = dev_get_uclass_platdata(dev);
56 	if (!uc_pdata)
57 		return -ENXIO;
58 
59 	dev_desc = rockchip_get_bootdev();
60 	if (!dev_desc)
61 		return -EEXIST;
62 
63 	ret = part_get_info_by_name(dev_desc, uc_pdata->partition, &part_info);
64 	if (ret < 0) {
65 		AMP_E("\"%s\" find partition \"%s\" failed\n",
66 		      uc_pdata->desc, uc_pdata->partition);
67 		return ret;
68 	}
69 
70 	ret = bidram_reserve_by_name(uc_pdata->partition,
71 				     uc_pdata->reserved_mem[0],
72 				     uc_pdata->reserved_mem[1]);
73 	if (ret) {
74 		AMP_E("Reserve \"%s\" region at 0x%08x - 0x%08x failed, ret=%d\n",
75 		      uc_pdata->desc, uc_pdata->reserved_mem[0],
76 		      uc_pdata->reserved_mem[0] + uc_pdata->reserved_mem[1], ret);
77 		return -ENOMEM;
78 	}
79 
80 	size = read_rockchip_image(dev_desc, &part_info,
81 				   (void *)(ulong)uc_pdata->load);
82 	if (size < 0) {
83 		AMP_E("\"%s\" load at 0x%08x failed\n",
84 		      uc_pdata->desc, uc_pdata->load);
85 		return size;
86 	}
87 
88 	flush_dcache_range(uc_pdata->load,
89 			   uc_pdata->load + ALIGN(size, ARCH_DMA_MINALIGN));
90 
91 	AMP_I("Brought up cpu[%x] on \"%s\" entry 0x%08x ...",
92 	      uc_pdata->cpu, uc_pdata->desc, uc_pdata->entry);
93 
94 	ret = psci_cpu_on(uc_pdata->cpu, uc_pdata->entry);
95 	if (ret) {
96 		printf("failed\n");
97 		return ret;
98 	}
99 	printf("OK\n");
100 
101 	return 0;
102 }
103 
104 static const struct dm_amp_ops rockchip_amp_ops = {
105 	.cpu_on = rockchip_amp_cpu_on,
106 };
107 
108 U_BOOT_DRIVER(rockchip_amp) = {
109 	.name	   = "rockchip_amp",
110 	.id	   = UCLASS_AMP,
111 	.ops	   = &rockchip_amp_ops,
112 };
113 
114 /* AMP bus driver as all amp parent */
115 static int rockchip_amp_bus_bind(struct udevice *dev)
116 {
117 	return amp_bind_children(dev, "rockchip_amp");
118 }
119 
120 static const struct udevice_id rockchip_amp_bus_match[] = {
121 	{ .compatible = "uboot,rockchip-amp", },
122 	{},
123 };
124 
125 U_BOOT_DRIVER(rockchip_amp_bus) = {
126 	.name	   = "rockchip_amp_bus",
127 	.id	   = UCLASS_SIMPLE_BUS,
128 	.of_match  = rockchip_amp_bus_match,
129 	.bind	   = rockchip_amp_bus_bind,
130 };
131