Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

memory: ti-aemif: Export aemif_*_cs_timings()

Export the aemif_set_cs_timing() and aemif_check_cs_timing() symbols so
they can be used by other drivers

Add a mutex to protect the CS configuration register from concurrent
accesses between the AEMIF and its 'children'.

Signed-off-by: Bastien Curutchet <bastien.curutchet@bootlin.com>
Reviewed-by: Miquel Raynal <miquel.raynal@bootlin.com>
Link: https://lore.kernel.org/r/20241204094319.1050826-7-bastien.curutchet@bootlin.com
[krzysztof: wrap aemif_set_cs_timings() at 80-char]
Signed-off-by: Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>

authored by

Bastien Curutchet and committed by
Krzysztof Kozlowski
df8e7860 a6d60e33

+46 -22
+14 -22
drivers/memory/ti-aemif.c
··· 13 13 #include <linux/err.h> 14 14 #include <linux/io.h> 15 15 #include <linux/kernel.h> 16 + #include <linux/memory/ti-aemif.h> 16 17 #include <linux/module.h> 18 + #include <linux/mutex.h> 17 19 #include <linux/of.h> 18 20 #include <linux/of_platform.h> 19 21 #include <linux/platform_device.h> ··· 82 80 #define CONFIG_MASK (EW(EW_MAX) | SSTROBE(SSTROBE_MAX) | ASIZE_MAX) 83 81 84 82 /** 85 - * struct aemif_cs_timings: structure to hold CS timings 86 - * @wstrobe: write strobe width, number of cycles - 1 87 - * @rstrobe: read strobe width, number of cycles - 1 88 - * @wsetup: write setup width, number of cycles - 1 89 - * @whold: write hold width, number of cycles - 1 90 - * @rsetup: read setup width, number of cycles - 1 91 - * @rhold: read hold width, number of cycles - 1 92 - * @ta: minimum turn around time, number of cycles - 1 93 - */ 94 - struct aemif_cs_timings { 95 - u32 wstrobe; 96 - u32 rstrobe; 97 - u32 wsetup; 98 - u32 whold; 99 - u32 rsetup; 100 - u32 rhold; 101 - u32 ta; 102 - }; 103 - 104 - /** 105 83 * struct aemif_cs_data: structure to hold CS parameters 106 84 * @timings: timings configuration 107 85 * @cs: chip-select number ··· 105 123 * @num_cs: number of assigned chip-selects 106 124 * @cs_offset: start number of cs nodes 107 125 * @cs_data: array of chip-select settings 126 + * @config_cs_lock: lock used to access CS configuration 108 127 */ 109 128 struct aemif_device { 110 129 void __iomem *base; ··· 114 131 u8 num_cs; 115 132 int cs_offset; 116 133 struct aemif_cs_data cs_data[NUM_CS]; 134 + struct mutex config_cs_lock; 117 135 }; 118 136 119 137 /** ··· 123 139 * 124 140 * @return: 0 if the timing configuration is valid, negative error number otherwise. 125 141 */ 126 - static int aemif_check_cs_timings(struct aemif_cs_timings *timings) 142 + int aemif_check_cs_timings(struct aemif_cs_timings *timings) 127 143 { 128 144 if (timings->ta > TA_MAX) 129 145 return -EINVAL; ··· 148 164 149 165 return 0; 150 166 } 167 + EXPORT_SYMBOL_GPL(aemif_check_cs_timings); 151 168 152 169 /** 153 170 * aemif_set_cs_timings() - Set the timing configuration of a given chip select. ··· 158 173 * 159 174 * @return: 0 on success, else negative errno. 160 175 */ 161 - static int aemif_set_cs_timings(struct aemif_device *aemif, u8 cs, struct aemif_cs_timings *timings) 176 + int aemif_set_cs_timings(struct aemif_device *aemif, u8 cs, 177 + struct aemif_cs_timings *timings) 162 178 { 163 179 unsigned int offset; 164 180 u32 val, set; ··· 181 195 182 196 offset = A1CR_OFFSET + cs * 4; 183 197 198 + mutex_lock(&aemif->config_cs_lock); 184 199 val = readl(aemif->base + offset); 185 200 val &= ~TIMINGS_MASK; 186 201 val |= set; 187 202 writel(val, aemif->base + offset); 203 + mutex_unlock(&aemif->config_cs_lock); 188 204 189 205 return 0; 190 206 } 207 + EXPORT_SYMBOL_GPL(aemif_set_cs_timings); 191 208 192 209 /** 193 210 * aemif_calc_rate - calculate timing data. ··· 246 257 if (data->enable_ss) 247 258 set |= ACR_SSTROBE_MASK; 248 259 260 + mutex_lock(&aemif->config_cs_lock); 249 261 val = readl(aemif->base + offset); 250 262 val &= ~CONFIG_MASK; 251 263 val |= set; 252 264 writel(val, aemif->base + offset); 265 + mutex_unlock(&aemif->config_cs_lock); 253 266 254 267 return aemif_set_cs_timings(aemif, data->cs - aemif->cs_offset, &data->timings); 255 268 } ··· 390 399 if (IS_ERR(aemif->base)) 391 400 return PTR_ERR(aemif->base); 392 401 402 + mutex_init(&aemif->config_cs_lock); 393 403 if (np) { 394 404 /* 395 405 * For every controller device node, there is a cs device node
+32
include/linux/memory/ti-aemif.h
··· 1 + /* SPDX-License-Identifier: GPL-2.0 */ 2 + 3 + #ifndef __MEMORY_TI_AEMIF_H 4 + #define __MEMORY_TI_AEMIF_H 5 + 6 + /** 7 + * struct aemif_cs_timings: structure to hold CS timing configuration 8 + * values are expressed in number of clock cycles - 1 9 + * @ta: minimum turn around time 10 + * @rhold: read hold width 11 + * @rstrobe: read strobe width 12 + * @rsetup: read setup width 13 + * @whold: write hold width 14 + * @wstrobe: write strobe width 15 + * @wsetup: write setup width 16 + */ 17 + struct aemif_cs_timings { 18 + u32 ta; 19 + u32 rhold; 20 + u32 rstrobe; 21 + u32 rsetup; 22 + u32 whold; 23 + u32 wstrobe; 24 + u32 wsetup; 25 + }; 26 + 27 + struct aemif_device; 28 + 29 + int aemif_set_cs_timings(struct aemif_device *aemif, u8 cs, struct aemif_cs_timings *timings); 30 + int aemif_check_cs_timings(struct aemif_cs_timings *timings); 31 + 32 + #endif // __MEMORY_TI_AEMIF_H