2013-01-21 14:54:26 +04:00
/*
* IPMMU / IPMMUI
* Copyright ( C ) 2012 Hideki EIRAKU
*
* 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 of the License .
*/
# include <linux/err.h>
# include <linux/export.h>
# include <linux/io.h>
# include <linux/platform_device.h>
# include <linux/slab.h>
# include <linux/platform_data/sh_ipmmu.h>
# include "shmobile-ipmmu.h"
# define IMCTR1 0x000
# define IMCTR2 0x004
# define IMASID 0x010
# define IMTTBR 0x014
# define IMTTBCR 0x018
# define IMCTR1_TLBEN (1 << 0)
# define IMCTR1_FLUSH (1 << 1)
static void ipmmu_reg_write ( struct shmobile_ipmmu * ipmmu , unsigned long reg_off ,
unsigned long data )
{
iowrite32 ( data , ipmmu - > ipmmu_base + reg_off ) ;
}
void ipmmu_tlb_flush ( struct shmobile_ipmmu * ipmmu )
{
if ( ! ipmmu )
return ;
2013-12-17 21:18:50 +04:00
spin_lock ( & ipmmu - > flush_lock ) ;
2013-01-21 14:54:26 +04:00
if ( ipmmu - > tlb_enabled )
ipmmu_reg_write ( ipmmu , IMCTR1 , IMCTR1_FLUSH | IMCTR1_TLBEN ) ;
else
ipmmu_reg_write ( ipmmu , IMCTR1 , IMCTR1_FLUSH ) ;
2013-12-17 21:18:50 +04:00
spin_unlock ( & ipmmu - > flush_lock ) ;
2013-01-21 14:54:26 +04:00
}
void ipmmu_tlb_set ( struct shmobile_ipmmu * ipmmu , unsigned long phys , int size ,
int asid )
{
if ( ! ipmmu )
return ;
2013-12-17 21:18:50 +04:00
spin_lock ( & ipmmu - > flush_lock ) ;
2013-01-21 14:54:26 +04:00
switch ( size ) {
default :
ipmmu - > tlb_enabled = 0 ;
break ;
case 0x2000 :
ipmmu_reg_write ( ipmmu , IMTTBCR , 1 ) ;
ipmmu - > tlb_enabled = 1 ;
break ;
case 0x1000 :
ipmmu_reg_write ( ipmmu , IMTTBCR , 2 ) ;
ipmmu - > tlb_enabled = 1 ;
break ;
case 0x800 :
ipmmu_reg_write ( ipmmu , IMTTBCR , 3 ) ;
ipmmu - > tlb_enabled = 1 ;
break ;
case 0x400 :
ipmmu_reg_write ( ipmmu , IMTTBCR , 4 ) ;
ipmmu - > tlb_enabled = 1 ;
break ;
case 0x200 :
ipmmu_reg_write ( ipmmu , IMTTBCR , 5 ) ;
ipmmu - > tlb_enabled = 1 ;
break ;
case 0x100 :
ipmmu_reg_write ( ipmmu , IMTTBCR , 6 ) ;
ipmmu - > tlb_enabled = 1 ;
break ;
case 0x80 :
ipmmu_reg_write ( ipmmu , IMTTBCR , 7 ) ;
ipmmu - > tlb_enabled = 1 ;
break ;
}
ipmmu_reg_write ( ipmmu , IMTTBR , phys ) ;
ipmmu_reg_write ( ipmmu , IMASID , asid ) ;
2013-12-17 21:18:50 +04:00
spin_unlock ( & ipmmu - > flush_lock ) ;
2013-01-21 14:54:26 +04:00
}
static int ipmmu_probe ( struct platform_device * pdev )
{
struct shmobile_ipmmu * ipmmu ;
struct resource * res ;
struct shmobile_ipmmu_platform_data * pdata = pdev - > dev . platform_data ;
ipmmu = devm_kzalloc ( & pdev - > dev , sizeof ( * ipmmu ) , GFP_KERNEL ) ;
if ( ! ipmmu ) {
dev_err ( & pdev - > dev , " cannot allocate device data \n " ) ;
return - ENOMEM ;
}
2013-12-17 21:18:50 +04:00
spin_lock_init ( & ipmmu - > flush_lock ) ;
2013-01-21 14:54:26 +04:00
ipmmu - > dev = & pdev - > dev ;
2014-02-21 19:54:53 +04:00
res = platform_get_resource ( pdev , IORESOURCE_MEM , 0 ) ;
ipmmu - > ipmmu_base = devm_ioremap_resource ( & pdev - > dev , res ) ;
if ( IS_ERR ( ipmmu - > ipmmu_base ) )
return PTR_ERR ( ipmmu - > ipmmu_base ) ;
2013-01-21 14:54:26 +04:00
ipmmu - > dev_names = pdata - > dev_names ;
ipmmu - > num_dev_names = pdata - > num_dev_names ;
platform_set_drvdata ( pdev , ipmmu ) ;
ipmmu_reg_write ( ipmmu , IMCTR1 , 0x0 ) ; /* disable TLB */
ipmmu_reg_write ( ipmmu , IMCTR2 , 0x0 ) ; /* disable PMB */
2014-02-21 19:54:53 +04:00
return ipmmu_iommu_init ( ipmmu ) ;
2013-01-21 14:54:26 +04:00
}
static struct platform_driver ipmmu_driver = {
. probe = ipmmu_probe ,
. driver = {
. name = " ipmmu " ,
} ,
} ;
static int __init ipmmu_init ( void )
{
return platform_driver_register ( & ipmmu_driver ) ;
}
subsys_initcall ( ipmmu_init ) ;