mtd: spinand: toshiba: Support for new Kioxia Serial NAND
[oweals/u-boot.git] / drivers / mailbox / tegra-hsp.c
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * Copyright (c) 2016, NVIDIA CORPORATION.
4  */
5
6 #include <common.h>
7 #include <log.h>
8 #include <malloc.h>
9 #include <asm/io.h>
10 #include <dm.h>
11 #include <mailbox-uclass.h>
12 #include <dt-bindings/mailbox/tegra186-hsp.h>
13 #include <linux/bitops.h>
14
15 #define TEGRA_HSP_INT_DIMENSIONING              0x380
16 #define TEGRA_HSP_INT_DIMENSIONING_NSI_SHIFT    16
17 #define TEGRA_HSP_INT_DIMENSIONING_NSI_MASK     0xf
18 #define TEGRA_HSP_INT_DIMENSIONING_NDB_SHIFT    12
19 #define TEGRA_HSP_INT_DIMENSIONING_NDB_MASK     0xf
20 #define TEGRA_HSP_INT_DIMENSIONING_NAS_SHIFT    8
21 #define TEGRA_HSP_INT_DIMENSIONING_NAS_MASK     0xf
22 #define TEGRA_HSP_INT_DIMENSIONING_NSS_SHIFT    4
23 #define TEGRA_HSP_INT_DIMENSIONING_NSS_MASK     0xf
24 #define TEGRA_HSP_INT_DIMENSIONING_NSM_SHIFT    0
25 #define TEGRA_HSP_INT_DIMENSIONING_NSM_MASK     0xf
26
27 #define TEGRA_HSP_DB_REG_TRIGGER        0x0
28 #define TEGRA_HSP_DB_REG_ENABLE         0x4
29 #define TEGRA_HSP_DB_REG_RAW            0x8
30 #define TEGRA_HSP_DB_REG_PENDING        0xc
31
32 #define TEGRA_HSP_DB_ID_CCPLEX          1
33 #define TEGRA_HSP_DB_ID_BPMP            3
34 #define TEGRA_HSP_DB_ID_NUM             7
35
36 struct tegra_hsp {
37         fdt_addr_t regs;
38         uint32_t db_base;
39 };
40
41 static uint32_t *tegra_hsp_reg(struct tegra_hsp *thsp, uint32_t db_id,
42                                uint32_t reg)
43 {
44         return (uint32_t *)(thsp->regs + thsp->db_base + (db_id * 0x100) + reg);
45 }
46
47 static uint32_t tegra_hsp_readl(struct tegra_hsp *thsp, uint32_t db_id,
48                                 uint32_t reg)
49 {
50         uint32_t *r = tegra_hsp_reg(thsp, db_id, reg);
51         return readl(r);
52 }
53
54 static void tegra_hsp_writel(struct tegra_hsp *thsp, uint32_t val,
55                              uint32_t db_id, uint32_t reg)
56 {
57         uint32_t *r = tegra_hsp_reg(thsp, db_id, reg);
58
59         writel(val, r);
60         readl(r);
61 }
62
63 static int tegra_hsp_db_id(ulong chan_id)
64 {
65         switch (chan_id) {
66         case (HSP_MBOX_TYPE_DB << 16) | HSP_DB_MASTER_BPMP:
67                 return TEGRA_HSP_DB_ID_BPMP;
68         default:
69                 debug("Invalid channel ID\n");
70                 return -EINVAL;
71         }
72 }
73
74 static int tegra_hsp_of_xlate(struct mbox_chan *chan,
75                               struct ofnode_phandle_args *args)
76 {
77         debug("%s(chan=%p)\n", __func__, chan);
78
79         if (args->args_count != 2) {
80                 debug("Invaild args_count: %d\n", args->args_count);
81                 return -EINVAL;
82         }
83
84         chan->id = (args->args[0] << 16) | args->args[1];
85
86         return 0;
87 }
88
89 static int tegra_hsp_request(struct mbox_chan *chan)
90 {
91         int db_id;
92
93         debug("%s(chan=%p)\n", __func__, chan);
94
95         db_id = tegra_hsp_db_id(chan->id);
96         if (db_id < 0) {
97                 debug("tegra_hsp_db_id() failed: %d\n", db_id);
98                 return -EINVAL;
99         }
100
101         return 0;
102 }
103
104 static int tegra_hsp_free(struct mbox_chan *chan)
105 {
106         debug("%s(chan=%p)\n", __func__, chan);
107
108         return 0;
109 }
110
111 static int tegra_hsp_send(struct mbox_chan *chan, const void *data)
112 {
113         struct tegra_hsp *thsp = dev_get_priv(chan->dev);
114         int db_id;
115
116         debug("%s(chan=%p, data=%p)\n", __func__, chan, data);
117
118         db_id = tegra_hsp_db_id(chan->id);
119         tegra_hsp_writel(thsp, 1, db_id, TEGRA_HSP_DB_REG_TRIGGER);
120
121         return 0;
122 }
123
124 static int tegra_hsp_recv(struct mbox_chan *chan, void *data)
125 {
126         struct tegra_hsp *thsp = dev_get_priv(chan->dev);
127         uint32_t db_id = TEGRA_HSP_DB_ID_CCPLEX;
128         uint32_t val;
129
130         debug("%s(chan=%p, data=%p)\n", __func__, chan, data);
131
132         val = tegra_hsp_readl(thsp, db_id, TEGRA_HSP_DB_REG_RAW);
133         if (!(val & BIT(chan->id)))
134                 return -ENODATA;
135
136         tegra_hsp_writel(thsp, BIT(chan->id), db_id, TEGRA_HSP_DB_REG_RAW);
137
138         return 0;
139 }
140
141 static int tegra_hsp_bind(struct udevice *dev)
142 {
143         debug("%s(dev=%p)\n", __func__, dev);
144
145         return 0;
146 }
147
148 static int tegra_hsp_probe(struct udevice *dev)
149 {
150         struct tegra_hsp *thsp = dev_get_priv(dev);
151         u32 val;
152         int nr_sm, nr_ss, nr_as;
153
154         debug("%s(dev=%p)\n", __func__, dev);
155
156         thsp->regs = devfdt_get_addr(dev);
157         if (thsp->regs == FDT_ADDR_T_NONE)
158                 return -ENODEV;
159
160         val = readl(thsp->regs + TEGRA_HSP_INT_DIMENSIONING);
161         nr_sm = (val >> TEGRA_HSP_INT_DIMENSIONING_NSM_SHIFT) &
162                 TEGRA_HSP_INT_DIMENSIONING_NSM_MASK;
163         nr_ss = (val >> TEGRA_HSP_INT_DIMENSIONING_NSS_SHIFT) &
164                 TEGRA_HSP_INT_DIMENSIONING_NSS_MASK;
165         nr_as = (val >> TEGRA_HSP_INT_DIMENSIONING_NAS_SHIFT) &
166                 TEGRA_HSP_INT_DIMENSIONING_NAS_MASK;
167
168         thsp->db_base = (1 + (nr_sm >> 1) + nr_ss + nr_as) << 16;
169
170         return 0;
171 }
172
173 static const struct udevice_id tegra_hsp_ids[] = {
174         { .compatible = "nvidia,tegra186-hsp" },
175         { }
176 };
177
178 struct mbox_ops tegra_hsp_mbox_ops = {
179         .of_xlate = tegra_hsp_of_xlate,
180         .request = tegra_hsp_request,
181         .rfree = tegra_hsp_free,
182         .send = tegra_hsp_send,
183         .recv = tegra_hsp_recv,
184 };
185
186 U_BOOT_DRIVER(tegra_hsp) = {
187         .name = "tegra-hsp",
188         .id = UCLASS_MAILBOX,
189         .of_match = tegra_hsp_ids,
190         .bind = tegra_hsp_bind,
191         .probe = tegra_hsp_probe,
192         .priv_auto_alloc_size = sizeof(struct tegra_hsp),
193         .ops = &tegra_hsp_mbox_ops,
194 };