Orange Pi5 kernel

Deprecated Linux kernel 5.10.110 for OrangePi 5/5B/5+ boards

3 Commits   0 Branches   0 Tags
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   1) // SPDX-License-Identifier: GPL-2.0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   2) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   3)  * u8500 HWSEM driver
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   4)  *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   5)  * Copyright (C) 2010-2011 ST-Ericsson
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   6)  *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   7)  * Implements u8500 semaphore handling for protocol 1, no interrupts.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   8)  *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   9)  * Author: Mathieu Poirier <mathieu.poirier@linaro.org>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  10)  * Heavily borrowed from the work of :
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  11)  *   Simon Que <sque@ti.com>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  12)  *   Hari Kanigeri <h-kanigeri2@ti.com>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  13)  *   Ohad Ben-Cohen <ohad@wizery.com>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  14)  */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  15) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  16) #include <linux/module.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  17) #include <linux/delay.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  18) #include <linux/io.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  19) #include <linux/slab.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  20) #include <linux/spinlock.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  21) #include <linux/hwspinlock.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  22) #include <linux/platform_device.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  23) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  24) #include "hwspinlock_internal.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  25) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  26) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  27)  * Implementation of STE's HSem protocol 1 without interrutps.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  28)  * The only masterID we allow is '0x01' to force people to use
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  29)  * HSems for synchronisation between processors rather than processes
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  30)  * on the ARM core.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  31)  */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  32) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  33) #define U8500_MAX_SEMAPHORE		32	/* a total of 32 semaphore */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  34) #define RESET_SEMAPHORE			(0)	/* free */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  35) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  36) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  37)  * CPU ID for master running u8500 kernel.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  38)  * Hswpinlocks should only be used to synchonise operations
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  39)  * between the Cortex A9 core and the other CPUs.  Hence
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  40)  * forcing the masterID to a preset value.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  41)  */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  42) #define HSEM_MASTER_ID			0x01
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  43) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  44) #define HSEM_REGISTER_OFFSET		0x08
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  45) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  46) #define HSEM_CTRL_REG			0x00
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  47) #define HSEM_ICRALL			0x90
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  48) #define HSEM_PROTOCOL_1			0x01
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  49) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  50) static int u8500_hsem_trylock(struct hwspinlock *lock)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  51) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  52) 	void __iomem *lock_addr = lock->priv;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  53) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  54) 	writel(HSEM_MASTER_ID, lock_addr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  55) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  56) 	/* get only first 4 bit and compare to masterID.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  57) 	 * if equal, we have the semaphore, otherwise
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  58) 	 * someone else has it.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  59) 	 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  60) 	return (HSEM_MASTER_ID == (0x0F & readl(lock_addr)));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  61) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  62) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  63) static void u8500_hsem_unlock(struct hwspinlock *lock)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  64) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  65) 	void __iomem *lock_addr = lock->priv;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  66) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  67) 	/* release the lock by writing 0 to it */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  68) 	writel(RESET_SEMAPHORE, lock_addr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  69) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  70) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  71) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  72)  * u8500: what value is recommended here ?
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  73)  */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  74) static void u8500_hsem_relax(struct hwspinlock *lock)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  75) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  76) 	ndelay(50);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  77) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  78) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  79) static const struct hwspinlock_ops u8500_hwspinlock_ops = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  80) 	.trylock	= u8500_hsem_trylock,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  81) 	.unlock		= u8500_hsem_unlock,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  82) 	.relax		= u8500_hsem_relax,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  83) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  84) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  85) static int u8500_hsem_probe(struct platform_device *pdev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  86) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  87) 	struct hwspinlock_pdata *pdata = pdev->dev.platform_data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  88) 	struct hwspinlock_device *bank;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  89) 	struct hwspinlock *hwlock;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  90) 	void __iomem *io_base;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  91) 	int i, num_locks = U8500_MAX_SEMAPHORE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  92) 	ulong val;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  93) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  94) 	if (!pdata)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  95) 		return -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  96) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  97) 	io_base = devm_platform_ioremap_resource(pdev, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  98) 	if (IS_ERR(io_base))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  99) 		return PTR_ERR(io_base);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) 	/* make sure protocol 1 is selected */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) 	val = readl(io_base + HSEM_CTRL_REG);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) 	writel((val & ~HSEM_PROTOCOL_1), io_base + HSEM_CTRL_REG);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) 	/* clear all interrupts */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) 	writel(0xFFFF, io_base + HSEM_ICRALL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) 	bank = devm_kzalloc(&pdev->dev, struct_size(bank, lock, num_locks),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) 			    GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) 	if (!bank)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) 		return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) 	platform_set_drvdata(pdev, bank);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) 	for (i = 0, hwlock = &bank->lock[0]; i < num_locks; i++, hwlock++)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) 		hwlock->priv = io_base + HSEM_REGISTER_OFFSET + sizeof(u32) * i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) 	return devm_hwspin_lock_register(&pdev->dev, bank,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) 					 &u8500_hwspinlock_ops,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) 					 pdata->base_id, num_locks);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) static int u8500_hsem_remove(struct platform_device *pdev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) 	struct hwspinlock_device *bank = platform_get_drvdata(pdev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) 	void __iomem *io_base = bank->lock[0].priv - HSEM_REGISTER_OFFSET;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) 	/* clear all interrupts */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) 	writel(0xFFFF, io_base + HSEM_ICRALL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) 	return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) static struct platform_driver u8500_hsem_driver = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) 	.probe		= u8500_hsem_probe,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) 	.remove		= u8500_hsem_remove,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) 	.driver		= {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) 		.name	= "u8500_hsem",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) 	},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) static int __init u8500_hsem_init(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) 	return platform_driver_register(&u8500_hsem_driver);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) /* board init code might need to reserve hwspinlocks for predefined purposes */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) postcore_initcall(u8500_hsem_init);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) static void __exit u8500_hsem_exit(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) 	platform_driver_unregister(&u8500_hsem_driver);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) module_exit(u8500_hsem_exit);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) MODULE_LICENSE("GPL v2");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156) MODULE_DESCRIPTION("Hardware Spinlock driver for u8500");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157) MODULE_AUTHOR("Mathieu Poirier <mathieu.poirier@linaro.org>");