blob: 774c56f27c8b12a587fb96d5c5fe3ce36332007c [file] [log] [blame]
developere5e687d2023-08-08 16:05:33 +08001// SPDX-License-Identifier: GPL-2.0-or-later
2/*
3 * Copyright (c) 2023 MediaTek Inc. All Rights Reserved.
4 *
5 * Author: Ren-Ting Wang <ren-ting.wang@mediatek.com>
6 */
7
8#include <linux/io.h>
9#include <linux/err.h>
10#include <linux/types.h>
11#include <linux/device.h>
12#include <linux/platform_device.h>
13
developer0fb30d52023-12-04 09:51:36 +080014#include "tops/hwspinlock.h"
15#include "tops/tops.h"
developere5e687d2023-08-08 16:05:33 +080016
17#define SEMA_ID (BIT(CORE_AP))
18
19static void __iomem *base;
20
21static inline u32 hwspinlock_read(u32 reg)
22{
23 return readl(base + reg);
24}
25
26static inline void hwspinlock_write(u32 reg, u32 val)
27{
28 writel(val, base + reg);
29}
30
31static inline u32 __mtk_tops_hwspinlock_get_reg(enum hwspinlock_group grp, u32 slot)
32{
33 if (unlikely(slot >= HWSPINLOCK_SLOT_MAX || grp >= __HWSPINLOCK_GROUP_MAX))
34 return 0;
35
36 if (grp == HWSPINLOCK_GROUP_TOP)
37 return HWSPINLOCK_TOP_BASE + slot * 4;
38 else
39 return HWSPINLOCK_CLUST_BASE + slot * 4;
40}
41
42/*
43 * try take TOPS HW spinlock
44 * return 1 on success
45 * return 0 on failure
46 */
47int mtk_tops_hwspin_try_lock(enum hwspinlock_group grp, u32 slot)
48{
49 u32 reg = __mtk_tops_hwspinlock_get_reg(grp, slot);
50
51 WARN_ON(!reg);
52
53 hwspinlock_write(reg, SEMA_ID);
54
55 return hwspinlock_read(reg) == SEMA_ID ? 1 : 0;
56}
57
58void mtk_tops_hwspin_lock(enum hwspinlock_group grp, u32 slot)
59{
60 u32 reg = __mtk_tops_hwspinlock_get_reg(grp, slot);
61
62 WARN_ON(!reg);
63
64 do {
65 hwspinlock_write(reg, SEMA_ID);
66 } while (hwspinlock_read(reg) != SEMA_ID);
67}
68
69void mtk_tops_hwspin_unlock(enum hwspinlock_group grp, u32 slot)
70{
71 u32 reg = __mtk_tops_hwspinlock_get_reg(grp, slot);
72
73 WARN_ON(!reg);
74
75 if (hwspinlock_read(reg) == SEMA_ID)
76 hwspinlock_write(reg, SEMA_ID);
77}
78
79int mtk_tops_hwspinlock_init(struct platform_device *pdev)
80{
81 struct resource *res;
82
83 res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "tops-base");
84 if (!res)
85 return -ENXIO;
86
87 base = devm_ioremap(&pdev->dev, res->start, resource_size(res));
88 if (!base)
89 return -ENOMEM;
90
91 return 0;
92}