GNU Linux-libre 4.14.290-gnu1
[releases.git] / arch / metag / kernel / core_reg.c
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  *  Support for reading and writing Meta core internal registers.
4  *
5  *  Copyright (C) 2011 Imagination Technologies Ltd.
6  *
7  */
8
9 #include <linux/delay.h>
10 #include <linux/export.h>
11
12 #include <asm/core_reg.h>
13 #include <asm/global_lock.h>
14 #include <asm/hwthread.h>
15 #include <asm/io.h>
16 #include <asm/metag_mem.h>
17 #include <asm/metag_regs.h>
18
19 #define UNIT_BIT_MASK           TXUXXRXRQ_UXX_BITS
20 #define REG_BIT_MASK            TXUXXRXRQ_RX_BITS
21 #define THREAD_BIT_MASK         TXUXXRXRQ_TX_BITS
22
23 #define UNIT_SHIFTS             TXUXXRXRQ_UXX_S
24 #define REG_SHIFTS              TXUXXRXRQ_RX_S
25 #define THREAD_SHIFTS           TXUXXRXRQ_TX_S
26
27 #define UNIT_VAL(x)             (((x) << UNIT_SHIFTS) & UNIT_BIT_MASK)
28 #define REG_VAL(x)              (((x) << REG_SHIFTS) & REG_BIT_MASK)
29 #define THREAD_VAL(x)           (((x) << THREAD_SHIFTS) & THREAD_BIT_MASK)
30
31 /*
32  * core_reg_write() - modify the content of a register in a core unit.
33  * @unit:       The unit to be modified.
34  * @reg:        Register number within the unit.
35  * @thread:     The thread we want to access.
36  * @val:        The new value to write.
37  *
38  * Check asm/metag_regs.h for a list/defines of supported units (ie: TXUPC_ID,
39  * TXUTR_ID, etc), and regnums within the units (ie: TXMASKI_REGNUM,
40  * TXPOLLI_REGNUM, etc).
41  */
42 void core_reg_write(int unit, int reg, int thread, unsigned int val)
43 {
44         unsigned long flags;
45
46         /* TXUCT_ID has its own memory mapped registers */
47         if (unit == TXUCT_ID) {
48                 void __iomem *cu_reg = __CU_addr(thread, reg);
49                 metag_out32(val, cu_reg);
50                 return;
51         }
52
53         __global_lock2(flags);
54
55         /* wait for ready */
56         while (!(metag_in32(TXUXXRXRQ) & TXUXXRXRQ_DREADY_BIT))
57                 udelay(10);
58
59         /* set the value to write */
60         metag_out32(val, TXUXXRXDT);
61
62         /* set the register to write */
63         val = UNIT_VAL(unit) | REG_VAL(reg) | THREAD_VAL(thread);
64         metag_out32(val, TXUXXRXRQ);
65
66         /* wait for finish */
67         while (!(metag_in32(TXUXXRXRQ) & TXUXXRXRQ_DREADY_BIT))
68                 udelay(10);
69
70         __global_unlock2(flags);
71 }
72 EXPORT_SYMBOL(core_reg_write);
73
74 /*
75  * core_reg_read() - read the content of a register in a core unit.
76  * @unit:       The unit to be modified.
77  * @reg:        Register number within the unit.
78  * @thread:     The thread we want to access.
79  *
80  * Check asm/metag_regs.h for a list/defines of supported units (ie: TXUPC_ID,
81  * TXUTR_ID, etc), and regnums within the units (ie: TXMASKI_REGNUM,
82  * TXPOLLI_REGNUM, etc).
83  */
84 unsigned int core_reg_read(int unit, int reg, int thread)
85 {
86         unsigned long flags;
87         unsigned int val;
88
89         /* TXUCT_ID has its own memory mapped registers */
90         if (unit == TXUCT_ID) {
91                 void __iomem *cu_reg = __CU_addr(thread, reg);
92                 val = metag_in32(cu_reg);
93                 return val;
94         }
95
96         __global_lock2(flags);
97
98         /* wait for ready */
99         while (!(metag_in32(TXUXXRXRQ) & TXUXXRXRQ_DREADY_BIT))
100                 udelay(10);
101
102         /* set the register to read */
103         val = (UNIT_VAL(unit) | REG_VAL(reg) | THREAD_VAL(thread) |
104                                                         TXUXXRXRQ_RDnWR_BIT);
105         metag_out32(val, TXUXXRXRQ);
106
107         /* wait for finish */
108         while (!(metag_in32(TXUXXRXRQ) & TXUXXRXRQ_DREADY_BIT))
109                 udelay(10);
110
111         /* read the register value */
112         val = metag_in32(TXUXXRXDT);
113
114         __global_unlock2(flags);
115
116         return val;
117 }
118 EXPORT_SYMBOL(core_reg_read);