blob: b9ac9e51e45b6ae6f4a620525b8b48cd2f9781c0 [file] [log] [blame]
developer5d86c142023-12-06 14:18:27 +08001// SPDX-License-Identifier: GPL-2.0-or-later
2/*
3 * Copyright (c) 2023 MediaTek Inc. All Rights Reserved.
4 *
5 * Author: Frank-zj Lin <frank-zj.lin@mediatek.com>
6 */
7
8#include <linux/io.h>
9#include <linux/spinlock.h>
10#include <linux/types.h>
11
12#include "tops/internal.h"
13#include "tops/seq_gen.h"
14
15#define SEQ_GEN_L(idx) (TOPS_SEQ_GEN_BASE + (idx) * 0x20)
16#define SEQ_GEN_H(idx) (TOPS_SEQ_GEN_BASE + (idx) * 0x20 + 0x10)
17
18static void __iomem *base;
19
20static DECLARE_BITMAP(seq_gen_used, TOPS_SEQ_GEN_IDX_MAX);
21static DEFINE_SPINLOCK(seq_gen_used_lock);
22
23static inline u32 seq_gen_read(u32 reg)
24{
25 return readl(base + reg);
26}
27
28static inline void seq_gen_write(u32 reg, u32 val)
29{
30 writel(val, base + reg);
31}
32
33static inline int seq_gen_read_16(u32 seq_gen_idx, u16 *val)
34{
35 if (seq_gen_idx >= TOPS_SEQ_GEN_IDX_MAX)
36 return -EINVAL;
37
38 *val = (u16)seq_gen_read(SEQ_GEN_L(seq_gen_idx));
39
40 return 0;
41}
42
43static inline void seq_gen_write_16(u32 seq_gen_idx, u16 val)
44{
45 if (seq_gen_idx >= TOPS_SEQ_GEN_IDX_MAX)
46 return;
47
48 seq_gen_write(SEQ_GEN_L(seq_gen_idx), (u32)val);
49}
50
51static inline int seq_gen_read_32(u32 seq_gen_idx, u32 *val)
52{
53 u32 val_h, val_l;
54
55 if (seq_gen_idx >= TOPS_SEQ_GEN_IDX_MAX)
56 return -EINVAL;
57
58 val_l = seq_gen_read(SEQ_GEN_L(seq_gen_idx));
59 val_h = seq_gen_read(SEQ_GEN_H(seq_gen_idx));
60
61 if (val_l != 0xFFFF)
62 seq_gen_write(SEQ_GEN_H(seq_gen_idx), val_h);
63
64 *val = (val_h << 16) | val_l;
65
66 return 0;
67}
68
69static inline void seq_gen_write_32(u32 seq_gen_idx, u32 val)
70{
71 if (seq_gen_idx >= TOPS_SEQ_GEN_IDX_MAX)
72 return;
73
74 seq_gen_write(SEQ_GEN_L(seq_gen_idx), (val & 0xFFFF));
75 seq_gen_write(SEQ_GEN_H(seq_gen_idx), (val >> 16));
76}
77
78static void mtk_tops_seq_gen_set_16_no_lock(int seq_gen_idx, u16 val)
79{
80 if (unlikely(!test_bit(seq_gen_idx, seq_gen_used)))
81 return;
82
83 seq_gen_write_16(seq_gen_idx, val);
84}
85
86static void mtk_tops_seq_gen_set_32_no_lock(int seq_gen_idx, u32 val)
87{
88 if (unlikely(!test_bit(seq_gen_idx, seq_gen_used)))
89 return;
90
91 seq_gen_write_32(seq_gen_idx, val);
92}
93
94static int mtk_tops_seq_gen_next_16_no_lock(int seq_gen_idx, u16 *val)
95{
96 if (unlikely(!val || !test_bit(seq_gen_idx, seq_gen_used)))
97 return -EINVAL;
98
99 return seq_gen_read_16(seq_gen_idx, val);
100}
101
102static int mtk_tops_seq_gen_next_32_no_lock(int seq_gen_idx, u32 *val)
103{
104 if (unlikely(!val || !test_bit(seq_gen_idx, seq_gen_used)))
105 return -EINVAL;
106
107 return seq_gen_read_32(seq_gen_idx, val);
108}
109
110void mtk_tops_seq_gen_set_16(int seq_gen_idx, u16 val)
111{
112 unsigned long flag;
113
114 spin_lock_irqsave(&seq_gen_used_lock, flag);
115
116 mtk_tops_seq_gen_set_16_no_lock(seq_gen_idx, val);
117
118 spin_unlock_irqrestore(&seq_gen_used_lock, flag);
119}
120
121int mtk_tops_seq_gen_next_16(int seq_gen_idx, u16 *val)
122{
123 unsigned long flag;
124 int ret;
125
126 spin_lock_irqsave(&seq_gen_used_lock, flag);
127
128 ret = mtk_tops_seq_gen_next_16_no_lock(seq_gen_idx, val);
129
130 spin_unlock_irqrestore(&seq_gen_used_lock, flag);
131
132 return ret;
133}
134
135void mtk_tops_seq_gen_set_32(int seq_gen_idx, u32 val)
136{
137 unsigned long flag;
138
139 spin_lock_irqsave(&seq_gen_used_lock, flag);
140
141 mtk_tops_seq_gen_set_32_no_lock(seq_gen_idx, val);
142
143 spin_unlock_irqrestore(&seq_gen_used_lock, flag);
144}
145
146int mtk_tops_seq_gen_next_32(int seq_gen_idx, u32 *val)
147{
148 unsigned long flag;
149 int ret;
150
151 spin_lock_irqsave(&seq_gen_used_lock, flag);
152
153 ret = mtk_tops_seq_gen_next_32_no_lock(seq_gen_idx, val);
154
155 spin_unlock_irqrestore(&seq_gen_used_lock, flag);
156
157 return ret;
158}
159
160static int mtk_tops_seq_gen_alloc_no_lock(int *seq_gen_idx)
161{
162 if (!seq_gen_idx)
163 return -EINVAL;
164
165 *seq_gen_idx = find_first_zero_bit(seq_gen_used, TOPS_SEQ_GEN_IDX_MAX);
166 if (*seq_gen_idx == TOPS_SEQ_GEN_IDX_MAX) {
167 TOPS_NOTICE("Sequence generator exhausted\n");
168 return -ENOMEM;
169 }
170
171 set_bit(*seq_gen_idx, seq_gen_used);
172
173 return 0;
174}
175
176int mtk_tops_seq_gen_alloc(int *seq_gen_idx)
177{
178 unsigned long flag;
179 int ret;
180
181 spin_lock_irqsave(&seq_gen_used_lock, flag);
182
183 ret = mtk_tops_seq_gen_alloc_no_lock(seq_gen_idx);
184
185 spin_unlock_irqrestore(&seq_gen_used_lock, flag);
186
187 return ret;
188}
189
190static void mtk_tops_seq_gen_free_no_lock(int seq_gen_idx)
191{
192 clear_bit(seq_gen_idx, seq_gen_used);
193}
194
195void mtk_tops_seq_gen_free(int seq_gen_idx)
196{
197 unsigned long flag = 0;
198
199 spin_lock_irqsave(&seq_gen_used_lock, flag);
200
201 mtk_tops_seq_gen_free_no_lock(seq_gen_idx);
202
203 spin_unlock_irqrestore(&seq_gen_used_lock, flag);
204}
205
206int mtk_tops_seq_gen_init(struct platform_device *pdev)
207{
208 struct resource *res;
209
210 res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "tops-base");
211 if (!res)
212 return -ENXIO;
213
214 base = devm_ioremap(&pdev->dev, res->start, resource_size(res));
215 if (!base)
216 return -ENOMEM;
217
218 return 0;
219}