1 | /* SPDX-License-Identifier: GPL-2.0-only */ |
2 | /* |
3 | * Broadcom BCM63xx Processor Monitor Bus shared routines (SMP and reset) |
4 | * |
5 | * Copyright (C) 2015, Broadcom Corporation |
6 | * Author: Florian Fainelli <f.fainelli@gmail.com> |
7 | */ |
8 | #ifndef __BCM63XX_PMB_H |
9 | #define __BCM63XX_PMB_H |
10 | |
11 | #include <linux/io.h> |
12 | #include <linux/types.h> |
13 | #include <linux/delay.h> |
14 | #include <linux/err.h> |
15 | |
16 | /* PMB Master controller register */ |
17 | #define PMB_CTRL 0x00 |
18 | #define PMC_PMBM_START (1 << 31) |
19 | #define PMC_PMBM_TIMEOUT (1 << 30) |
20 | #define PMC_PMBM_SLAVE_ERR (1 << 29) |
21 | #define PMC_PMBM_BUSY (1 << 28) |
22 | #define PMC_PMBM_READ (0 << 20) |
23 | #define PMC_PMBM_WRITE (1 << 20) |
24 | #define PMB_WR_DATA 0x04 |
25 | #define PMB_TIMEOUT 0x08 |
26 | #define PMB_RD_DATA 0x0C |
27 | |
28 | #define PMB_BUS_ID_SHIFT 8 |
29 | |
30 | /* Perform the low-level PMB master operation, shared between reads and |
31 | * writes. |
32 | */ |
33 | static inline int __bpcm_do_op(void __iomem *master, unsigned int addr, |
34 | u32 off, u32 op) |
35 | { |
36 | unsigned int timeout = 1000; |
37 | u32 cmd; |
38 | |
39 | cmd = (PMC_PMBM_START | op | (addr & 0xff) << 12 | off); |
40 | writel(val: cmd, addr: master + PMB_CTRL); |
41 | do { |
42 | cmd = readl(addr: master + PMB_CTRL); |
43 | if (!(cmd & PMC_PMBM_START)) |
44 | return 0; |
45 | |
46 | if (cmd & PMC_PMBM_SLAVE_ERR) |
47 | return -EIO; |
48 | |
49 | if (cmd & PMC_PMBM_TIMEOUT) |
50 | return -ETIMEDOUT; |
51 | |
52 | udelay(1); |
53 | } while (timeout-- > 0); |
54 | |
55 | return -ETIMEDOUT; |
56 | } |
57 | |
58 | static inline int bpcm_rd(void __iomem *master, unsigned int addr, |
59 | u32 off, u32 *val) |
60 | { |
61 | int ret = 0; |
62 | |
63 | ret = __bpcm_do_op(master, addr, off: off >> 2, PMC_PMBM_READ); |
64 | *val = readl(addr: master + PMB_RD_DATA); |
65 | |
66 | return ret; |
67 | } |
68 | |
69 | static inline int bpcm_wr(void __iomem *master, unsigned int addr, |
70 | u32 off, u32 val) |
71 | { |
72 | int ret = 0; |
73 | |
74 | writel(val, addr: master + PMB_WR_DATA); |
75 | ret = __bpcm_do_op(master, addr, off: off >> 2, PMC_PMBM_WRITE); |
76 | |
77 | return ret; |
78 | } |
79 | |
80 | #endif /* __BCM63XX_PMB_H */ |
81 | |