blob: 774c56f27c8b12a587fb96d5c5fe3ce36332007c [file] [log] [blame]
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Copyright (c) 2023 MediaTek Inc. All Rights Reserved.
*
* Author: Ren-Ting Wang <ren-ting.wang@mediatek.com>
*/
#include <linux/io.h>
#include <linux/err.h>
#include <linux/types.h>
#include <linux/device.h>
#include <linux/platform_device.h>
#include "tops/hwspinlock.h"
#include "tops/tops.h"
#define SEMA_ID (BIT(CORE_AP))
static void __iomem *base;
static inline u32 hwspinlock_read(u32 reg)
{
return readl(base + reg);
}
static inline void hwspinlock_write(u32 reg, u32 val)
{
writel(val, base + reg);
}
static inline u32 __mtk_tops_hwspinlock_get_reg(enum hwspinlock_group grp, u32 slot)
{
if (unlikely(slot >= HWSPINLOCK_SLOT_MAX || grp >= __HWSPINLOCK_GROUP_MAX))
return 0;
if (grp == HWSPINLOCK_GROUP_TOP)
return HWSPINLOCK_TOP_BASE + slot * 4;
else
return HWSPINLOCK_CLUST_BASE + slot * 4;
}
/*
* try take TOPS HW spinlock
* return 1 on success
* return 0 on failure
*/
int mtk_tops_hwspin_try_lock(enum hwspinlock_group grp, u32 slot)
{
u32 reg = __mtk_tops_hwspinlock_get_reg(grp, slot);
WARN_ON(!reg);
hwspinlock_write(reg, SEMA_ID);
return hwspinlock_read(reg) == SEMA_ID ? 1 : 0;
}
void mtk_tops_hwspin_lock(enum hwspinlock_group grp, u32 slot)
{
u32 reg = __mtk_tops_hwspinlock_get_reg(grp, slot);
WARN_ON(!reg);
do {
hwspinlock_write(reg, SEMA_ID);
} while (hwspinlock_read(reg) != SEMA_ID);
}
void mtk_tops_hwspin_unlock(enum hwspinlock_group grp, u32 slot)
{
u32 reg = __mtk_tops_hwspinlock_get_reg(grp, slot);
WARN_ON(!reg);
if (hwspinlock_read(reg) == SEMA_ID)
hwspinlock_write(reg, SEMA_ID);
}
int mtk_tops_hwspinlock_init(struct platform_device *pdev)
{
struct resource *res;
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "tops-base");
if (!res)
return -ENXIO;
base = devm_ioremap(&pdev->dev, res->start, resource_size(res));
if (!base)
return -ENOMEM;
return 0;
}