| /* |
| * Broadcom BCM63xx Processor Monitor Bus shared routines (SMP and reset) |
| * |
| * Copyright (C) 2015, Broadcom Corporation |
| * Author: Florian Fainelli <f.fainelli@gmail.com> |
| * |
| * This program is free software; you can redistribute it and/or |
| * modify it under the terms of the GNU General Public License as |
| * published by the Free Software Foundation version 2. |
| * |
| * This program is distributed "as is" WITHOUT ANY WARRANTY of any |
| * kind, whether express or implied; without even the implied warranty |
| * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| * GNU General Public License for more details. |
| */ |
| #ifndef __BCM63XX_PMB_H |
| #define __BCM63XX_PMB_H |
| |
| #include <linux/io.h> |
| #include <linux/types.h> |
| #include <linux/delay.h> |
| #include <linux/err.h> |
| |
| /* PMB Master controller register */ |
| #define PMB_CTRL 0x00 |
| #define PMC_PMBM_START (1 << 31) |
| #define PMC_PMBM_TIMEOUT (1 << 30) |
| #define PMC_PMBM_SLAVE_ERR (1 << 29) |
| #define PMC_PMBM_BUSY (1 << 28) |
| #define PMC_PMBM_READ (0 << 20) |
| #define PMC_PMBM_WRITE (1 << 20) |
| #define PMB_WR_DATA 0x04 |
| #define PMB_TIMEOUT 0x08 |
| #define PMB_RD_DATA 0x0C |
| |
| #define PMB_BUS_ID_SHIFT 8 |
| |
| /* Perform the low-level PMB master operation, shared between reads and |
| * writes. |
| */ |
| static inline int __bpcm_do_op(void __iomem *master, unsigned int addr, |
| u32 off, u32 op) |
| { |
| unsigned int timeout = 1000; |
| u32 cmd; |
| |
| cmd = (PMC_PMBM_START | op | (addr & 0xff) << 12 | off); |
| writel(cmd, master + PMB_CTRL); |
| do { |
| cmd = readl(master + PMB_CTRL); |
| if (!(cmd & PMC_PMBM_START)) |
| return 0; |
| |
| if (cmd & PMC_PMBM_SLAVE_ERR) |
| return -EIO; |
| |
| if (cmd & PMC_PMBM_TIMEOUT) |
| return -ETIMEDOUT; |
| |
| udelay(1); |
| } while (timeout-- > 0); |
| |
| return -ETIMEDOUT; |
| } |
| |
| static inline int bpcm_rd(void __iomem *master, unsigned int addr, |
| u32 off, u32 *val) |
| { |
| int ret = 0; |
| |
| ret = __bpcm_do_op(master, addr, off >> 2, PMC_PMBM_READ); |
| *val = readl(master + PMB_RD_DATA); |
| |
| return ret; |
| } |
| |
| static inline int bpcm_wr(void __iomem *master, unsigned int addr, |
| u32 off, u32 val) |
| { |
| int ret = 0; |
| |
| writel(val, master + PMB_WR_DATA); |
| ret = __bpcm_do_op(master, addr, off >> 2, PMC_PMBM_WRITE); |
| |
| return ret; |
| } |
| |
| #endif /* __BCM63XX_PMB_H */ |