blob: 7843e467dcab7e9b6a100a8f29fc4a0b920e8898 [file] [log] [blame]
/*
* arch/arm/mach-zx297520v2/zx297520v2-clock.c
*
* Copyright (C) 2015 ZTE-TSP
*
* 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; either version 2 of the License, or
* (at your option) any later version.
*
*/
#include <linux/kernel.h>
#include <linux/interrupt.h>
#include <linux/of_device.h>
#include <linux/of_address.h>
#include <linux/of_irq.h>
#include <linux/platform_device.h>
#include <linux/delay.h>
#include <linux/mutex.h>
#include <linux/device.h>
#include <linux/module.h>
#include <linux/cdev.h>
#include <linux/fs.h>
#include <linux/uaccess.h>
#include <linux/soc/zte/spinlock.h>
#define USE_HW_SPINLOCK 1
#define SHARED_DEVICE_REG1 (hwlock_reg_base + 0x170)
#define SHARED_DEVICE_REG2 (hwlock_reg_base + 0x174)
#define SHARED_DEVICE_REG3 (hwlock_reg_base + 0x178)
#define SHARED_DEVICE_REG4 (hwlock_reg_base + 0x17C)
#if USE_HW_SPINLOCK
#define MACH_NR_SFLOCKS SFLOCK_NUM
#define MACH_NR_HWLOCKS HWLOCK_NUM
#define SELF_CORE_ID CORE_ID_AP
/* now use 8*MACH_NR_SFLOCKS bytes */
#define SOFTLOCK_DESC_BASE (sf_base)//(SPINLOCK_SOFTLOCK_BASE)
#define SPINLOCK_DEBUG 1
#if SPINLOCK_DEBUG
#define zspinlock_debug(fmt, ...) \
printk(KERN_INFO fmt, ##__VA_ARGS__)
#else
#define zspinlock_debug(fmt, ...)
#endif
#define zspinlock_assert(_EXP) BUG_ON(!_EXP)//ZDRV_ASSERT(_EXP)
static DEFINE_MUTEX(zspinlock_mutex);
static unsigned long s_hwSpinlockMsr[HWLOCK_NUM];
/****************************************************************************
* Types
****************************************************************************/
struct zte_softlock_desc {
unsigned long used;
unsigned long owner;
};
/**************************************************************************
* Global Variables *
**************************************************************************/
static volatile struct zte_softlock_desc *softlock_desc[MACH_NR_SFLOCKS];
static void __iomem __force *hwlock_reg_base;
static void __iomem __force *sf_base;
static void __iomem __force *hwlock_regs[MACH_NR_HWLOCKS] ;
/*
=
{
SHARED_DEVICE_REG1,
SHARED_DEVICE_REG2,
SHARED_DEVICE_REG3,
SHARED_DEVICE_REG4
};
*/
extern void msleep(unsigned int msecs);
/*******************************************************************************
* Function: _hw_spin_lock
* Description:»ñȡӲ¼þËø£¬id 0~3
* Parameters:
* Input:
*
* Output:
*
* Returns:
*
*
* Others:
********************************************************************************/
static void _hw_spin_lock(unsigned long hwid)
{
unsigned long tmp;
unsigned long msr;
local_irq_save(msr);
s_hwSpinlockMsr[hwid] = msr;
while(ioread32(hwlock_regs[hwid])&0x1);
tmp = ioread32(hwlock_regs[hwid]);
tmp &= 0x00ffffff;
tmp |= (SELF_CORE_ID&0xff)<<24;
iowrite32(tmp, hwlock_regs[hwid]);
}
/*******************************************************************************
* Function: _hw_spin_unlock
* Description:ÊÍ·ÅÓ²¼þËø£¬id 0~3
* Parameters:
* Input:
*
* Output:
*
* Returns:
*
*
* Others:
********************************************************************************/
static void _hw_spin_unlock(unsigned long hwid)
{
unsigned long tmp;
if(SELF_CORE_ID != (ioread32(hwlock_regs[hwid])&0xff000000)>>24){
zspinlock_assert(0);
}
tmp = ioread32(hwlock_regs[hwid]);
tmp &= 0x00fffffe;
iowrite32(tmp, hwlock_regs[hwid]);
local_irq_restore(s_hwSpinlockMsr[hwid]);
}
/*******************************************************************************
* Function: hw_spin_lock
* Description:»ñȡӲ¼þËø£¬id 0~2£¬
* id 3±£Áô¸øÈí¼þËøÊ¹Óã¬ÍⲿÇý¶¯²»¿ÉÓá£
* Parameters:
* Input:
*
* Output:
*
* Returns:
*
*
* Others:
********************************************************************************/
void hw_spin_lock(emhw_lock_id hwid)
{
_hw_spin_lock(hwid);
// zspinlock_debug("cpu %d gets %d hardware lock!/n",SELF_CORE_ID,hwid);
}
/*******************************************************************************
* Function: hw_spin_unlock
* Description:Çý¶¯ÊÍ·ÅÓ²¼þËø£¬id 0~2
* Parameters:
* Input:
*
* Output:
*
* Returns:
*
*
* Others:
********************************************************************************/
void hw_spin_unlock(emhw_lock_id hwid)
{
_hw_spin_unlock(hwid);
// zspinlock_debug("cpu %d releases %d hardware lock!/n",SELF_CORE_ID,hwid);
}
/*******************************************************************************
* Function: soft_spin_lock
* Description:Çý¶¯»ñµÃÈí¼þËø½Ó¿Ú
* Parameters:
* Input: sfid: Èí¼þËøid¡£
* coreid: ±£³ÖidºÅΪsfidÈí¼þËøµÄcpuid¡£
* Output:
*
* Returns:
*
*
* Others:
********************************************************************************/
void soft_spin_lock(emsf_lock_id sfid)
{
static unsigned long lock_count = 0;
softlock_loop:
while(softlock_desc[sfid]->owner != SELF_CORE_ID && softlock_desc[sfid]->used)
{
lock_count++;
if(lock_count == 1000)
{
lock_count = 0;
msleep(5);
}
}
_hw_spin_lock(SOFTLOCK_HWLOCK);
if(softlock_desc[sfid]->owner != SELF_CORE_ID && softlock_desc[sfid]->used)
{
_hw_spin_unlock(SOFTLOCK_HWLOCK);
goto softlock_loop;
}
softlock_desc[sfid]->used ++;
softlock_desc[sfid]->owner = SELF_CORE_ID;
_hw_spin_unlock(SOFTLOCK_HWLOCK);
//zspinlock_debug("cpu %d releases %d software lock!/n",SELF_CORE_ID,sfid);
}
#if 1
int soft_spin_lock_printf(emsf_lock_id sfid)
{
static unsigned long lock_count = 0;
softlock_loop:
while(softlock_desc[sfid]->owner != SELF_CORE_ID && softlock_desc[sfid]->used)
{
ndelay(1);
lock_count++;
if(lock_count >= 5000)
{
lock_count = 0;
return -1;
}
}
_hw_spin_lock(SOFTLOCK_HWLOCK);
if(softlock_desc[sfid]->owner != SELF_CORE_ID && softlock_desc[sfid]->used)
{
_hw_spin_unlock(SOFTLOCK_HWLOCK);
goto softlock_loop;
}
softlock_desc[sfid]->used ++;
softlock_desc[sfid]->owner = SELF_CORE_ID;
_hw_spin_unlock(SOFTLOCK_HWLOCK);
return 0;
}
#endif
/*******************************************************************************
* Function: soft_spin_unlock
* Description:Óësoft_spin_lock¶ÔÓ¦µÄÊÍ·ÅÈí¼þËø½Ó¿Ú¡£
* Parameters:
* Input:
*
* Output:
*
* Returns:
*
*
* Others:
********************************************************************************/
void soft_spin_unlock(emsf_lock_id sfid)
{
if(softlock_desc[sfid]->used){
if(SELF_CORE_ID != softlock_desc[sfid]->owner){
zspinlock_assert(0);
}
_hw_spin_lock(SOFTLOCK_HWLOCK);
softlock_desc[sfid]->used --;
if(softlock_desc[sfid]->used == 0) {
softlock_desc[sfid]->owner = 0x0;
}
_hw_spin_unlock(SOFTLOCK_HWLOCK);
//zspinlock_debug("cpu %d releases %d software lock!/n",SELF_CORE_ID,sfid);
}
}
/*******************************************************************************
* Function: soft_spin_lock_psm
* Description:Çý¶¯»ñµÃÈí¼þËø½Ó¿Ú
* Parameters:
* Input: sfid: Èí¼þËøid¡£
* coreid: ±£³ÖidºÅΪsfidÈí¼þËøµÄcpuid¡£
* Output:
*
* Returns:
*
*
* Others:
********************************************************************************/
void soft_spin_lock_psm(emsf_lock_id sfid)
{
softlock_loop:
while(softlock_desc[sfid]->owner != SELF_CORE_ID && softlock_desc[sfid]->used)
{
}
_hw_spin_lock(SOFTLOCK_HWLOCK);
if(softlock_desc[sfid]->owner != SELF_CORE_ID && softlock_desc[sfid]->used)
{
_hw_spin_unlock(SOFTLOCK_HWLOCK);
goto softlock_loop;
}
softlock_desc[sfid]->used ++;
softlock_desc[sfid]->owner = SELF_CORE_ID;
_hw_spin_unlock(SOFTLOCK_HWLOCK);
//zspinlock_debug("cpu %d releases %d software lock!/n",SELF_CORE_ID,sfid);
}
/*******************************************************************************
* Function: soft_spin_unlock_psm
* Description:Óësoft_spin_lock_psm¶ÔÓ¦µÄÊÍ·ÅÈí¼þËø½Ó¿Ú¡£
* Parameters:
* Input:
*
* Output:
*
* Returns:
*
*
* Others:
********************************************************************************/
void soft_spin_unlock_psm(emsf_lock_id sfid)
{
soft_spin_unlock(sfid);
}
/*******************************************************************************
* Function: reg_spin_lock
* Description:Çý¶¯»ñµÃ¼Ä´æÆ÷Ëø½Ó¿Ú
* Parameters:
* Input:
* Output:
*
* Returns:
*
*
* Others:
********************************************************************************/
void reg_spin_lock(void)
{
_hw_spin_lock(REGLOCK_HWLOCK);
softlock_desc[REG_SFLOCK]->owner = SELF_CORE_ID;
}
EXPORT_SYMBOL(reg_spin_lock);
/*******************************************************************************
* Function: reg_spin_unlock
* Description:Óëreg_spin_lock¶ÔÓ¦µÄÊͷżĴæÆ÷Ëø½Ó¿Ú¡£
* Parameters:
* Input:
*
* Output:
*
* Returns:
*
*
* Others:
********************************************************************************/
void reg_spin_unlock(void)
{
softlock_desc[REG_SFLOCK]->owner = 0x0;
_hw_spin_unlock(REGLOCK_HWLOCK);
}
EXPORT_SYMBOL(reg_spin_unlock);
/*******************************************************************************
* Function: softspinlock_init
* Description:Èí¼þËø³õʼ»¯¡£
* Parameters:
* Input:
*
* Output:
*
* Returns:
*
*
* Others:
********************************************************************************/
int softspinlock_init(void)
{
int i;
for(i = 0; i<MACH_NR_SFLOCKS; i++){
softlock_desc[i] =
(struct zte_softlock_desc *)(SOFTLOCK_DESC_BASE +i*sizeof(struct zte_softlock_desc));
//softlock_desc[i]->used = 0;
//softlock_desc[i]->owner= CORE_ID_NUM;
}
zspinlock_debug("softspinlock init success base=0x%x!",(int)SOFTLOCK_DESC_BASE);
return 0;
}
typedef struct _zx29_softspinlock_ser
{
struct cdev cdev;
struct module *owner;
struct class *classes;
const struct file_operations *ops;
}zx29_softspinlock_ser;
static zx29_softspinlock_ser softspinlock_zx29 = {
.owner = THIS_MODULE,
};
int soft_spin_lock_get(emsf_lock_id sfid)
{
if(sfid>=SFLOCK_NUM)
return -EFAULT;
if(softlock_desc[sfid]->owner != SELF_CORE_ID && softlock_desc[sfid]->used)
return 1;
else
return 0;
}
static long softspinlock_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
{
int ret = 0;
char k_arg;
switch(cmd)
{
case SPINLOCK_GET_STATUS:
ret = copy_from_user(&k_arg, arg, sizeof(char));
if (ret)
return -EFAULT;
if(k_arg>= SFLOCK_NUM)
return -EFAULT;
k_arg = (char)soft_spin_lock_get(k_arg);
ret = copy_to_user(arg,&k_arg, sizeof(char));
if (ret)
return -EFAULT;
break;
default:
return -EPERM;
}
return ret;
}
static const struct file_operations softspinlock_ops = {
.owner = THIS_MODULE,
.unlocked_ioctl = softspinlock_ioctl,
};
static int __init softspinlock_dev_init(void)
{
int ret = 0;
dev_t dev;
softspinlock_zx29.ops = &softspinlock_ops;
ret = alloc_chrdev_region(&dev, 0, 1, "softspinlock");
if (ret)
{
printk(KERN_ERR "%s: softspinlock failed to allocate char dev region\n",
__FILE__);
return ret;
}
cdev_init(&softspinlock_zx29.cdev, &softspinlock_ops);
softspinlock_zx29.cdev.owner = softspinlock_zx29.owner;
ret = cdev_add(&softspinlock_zx29.cdev, dev, 1);
if (ret)
{
unregister_chrdev_region(dev, 1);
printk(KERN_ERR "%s: softspinlock failed to add cdev\n",
__FILE__);
return ret;
}
softspinlock_zx29.classes = class_create(THIS_MODULE, "softspinlock");
if (IS_ERR(softspinlock_zx29.classes))
return PTR_ERR(softspinlock_zx29.classes);
device_create(softspinlock_zx29.classes, NULL, dev, NULL, "softspinlock");
printk("[xxx] softspinlock dev inited! \n");
return ret;
}
void zx_spinlock_init(void __iomem *spinlock_base)
{
void __iomem **data = (void __iomem **)spinlock_base;
hwlock_reg_base = data[0];
sf_base = data[1];
hwlock_regs[0] = SHARED_DEVICE_REG1;
hwlock_regs[1] = SHARED_DEVICE_REG2;
hwlock_regs[2] = SHARED_DEVICE_REG3;
hwlock_regs[3] = SHARED_DEVICE_REG4;
softspinlock_init();
}
//arch_initcall(softspinlock_init);
#else
int softspinlock_init(void){return 0;}
void reg_spin_lock(void){}
void reg_spin_unlock(void){}
void soft_spin_lock(emsf_lock_id sfid){}
void soft_spin_unlock(emsf_lock_id sfid){}
void soft_spin_lock_psm(emsf_lock_id sfid){}
void soft_spin_unlock_psm(emsf_lock_id sfid){}
void hw_spin_lock(emhw_lock_id hwid){}
void hw_spin_unlock(emhw_lock_id hwid){}
static int __init softspinlock_dev_init(void){return 0;}
#endif
module_init(softspinlock_dev_init);