/*
 * include/asm-arm/arch-cxd4105/memory.h
 *
 * memory address definitions
 *
 * Copyright 2005,2006 Sony Corporation
 *
 * This code is based on include/asm-arm/arch-integrator/memory.h.
 */
/*
 *  linux/include/asm-arm/arch-integrator/mmu.h
 *
 *  Copyright (C) 1999 ARM Limited
 *
 * 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.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */
#ifndef __ASM_ARCH_MEMORY_H
#define __ASM_ARCH_MEMORY_H
#include <asm/page.h>

#ifdef __ASSEMBLY__
#define PHYS_OFFSET	(CONFIG_CXD4105_PHYS_OFFSET)
#define BUS_OFFSET	(CONFIG_CXD4105_PHYS_OFFSET)
#else
#define PHYS_OFFSET	((unsigned long)CONFIG_CXD4105_PHYS_OFFSET)
#define BUS_OFFSET	((unsigned long)CONFIG_CXD4105_PHYS_OFFSET)
#endif /* __ASSEMBLY__ */

/*
 * Virtual view <-> DMA view memory address translations
 * virt_to_bus: Used to translate the virtual address to an
 *              address suitable to be passed to set_dma_addr
 * bus_to_virt: Used to convert an address for DMA operations
 *              to an address that the kernel can use.
 */
#define __virt_to_bus__is_a_macro
#define __bus_to_virt__is_a_macro
#define __virt_to_bus(x)	__virt_to_phys((unsigned long)(x))
#define __bus_to_virt(x)	__phys_to_virt((unsigned long)(x))

#if defined(CONFIG_DISCONTIGMEM) || defined(CONFIG_SPARSEMEM)
/*
  a trick:
  0x20000000 - 0x2fffffff -> 0x40000000 - 0x4fffffff
  0x30000000 - 0x3fffffff -> 0x30000000 - 0x3fffffff
 */
#define __PREMODIFIER           (0x30000000)
#define __AFTMODIFIER           (0x30000000)
#define __MOD(x)                (((x) ^ __PREMODIFIER) + __AFTMODIFIER)
#define __RMOD(x)               (((x) - __AFTMODIFIER) ^ __PREMODIFIER)

#define __virt_to_phys(x)	__RMOD((x) - PAGE_OFFSET + PHYS_OFFSET)
#define __phys_to_virt(x)	(__MOD(x) - PHYS_OFFSET + PAGE_OFFSET)

#ifdef CONFIG_MEMORY_HOTPLUG
#define VA_MAX_HOTPLUG_MEM		(0xd4000000)
#endif

/*
 * To use DDR memory for debugging or other purpose
 * 
 * 	node 0:  0x3xxxxxxx - 0x3xxxxxxx -> 0xC0000000 - 0xCxxxxxxx
 * 	node 1:  0x2xxxxxxx - 0x2xxxxxxx -> 0xCxxxxxxx - xxxxxxxxxx
 */
#endif /* CONFIG_DISCONTIGMEM || CONFIG_SPARSEMEM */

#ifdef CONFIG_DISCONTIGMEM
#define NR_MEM_SECTIONS (MAX_NUMNODES)
/*
 * Given a kernel address, find the home node of the underlying memory.
 * All memory except node 0 is mapped into High Memory so
 */
#define KVADDR_TO_NID(addr)     __kaddr_to_nid((unsigned long)(addr))

/*
 * Given a page frame number, convert it to a node id.
 */
#define PFN_TO_NID(pfn)         __pfn_to_nid(pfn)

/*
 * Given a kaddr, ADDR_TO_MAPBASE finds the owning node of the memory
 * and return the mem_map of that node.
 */
#define ADDR_TO_MAPBASE(kaddr)	NODE_MEM_MAP(KVADDR_TO_NID(kaddr))

/*
 * Given a page frame number, find the owning node of the memory
 * and return the mem_map of that node.
 */
#define PFN_TO_MAPBASE(pfn)	NODE_MEM_MAP(PFN_TO_NID(pfn))

/*
 * Given a kaddr, LOCAL_MEM_MAP finds the owning node of the memory
 * and returns the index corresponding to the appropriate page in the
 * node's mem_map.
 */
#define LOCAL_MAP_NR(kaddr) __local_map_nr((unsigned long)(kaddr))

#define LOCAL_MAP_NR2(pfn, nid) ((pfn) - cxd4105_nodeinfo[(nid)].spfn)


#ifndef __ASSEMBLY__
static const struct _nodeinfo {
	unsigned long spfn;  /* start pfn */
	unsigned long epfn;
	unsigned long svirt; /* start kaddr */
	unsigned long evirt;
} cxd4105_nodeinfo [] = {
	{
		.spfn = (CONFIG_CXD4105_PHYS_OFFSET) >> PAGE_SHIFT,
		.epfn = (CONFIG_CXD4105_PHYS_OFFSET + CONFIG_CXD4105_SIZE_NODE0) >> PAGE_SHIFT,
		.svirt = __phys_to_virt(CONFIG_CXD4105_PHYS_OFFSET),
		.evirt = __phys_to_virt(CONFIG_CXD4105_PHYS_OFFSET + CONFIG_CXD4105_SIZE_NODE0),
	},
	{
		.spfn = (CONFIG_CXD4105_PHYS_OFFSET_NODE1) >> PAGE_SHIFT,
		.epfn = (CONFIG_CXD4105_PHYS_OFFSET_NODE1 + CONFIG_CXD4105_SIZE_NODE1) >> PAGE_SHIFT,
		.svirt = __phys_to_virt(CONFIG_CXD4105_PHYS_OFFSET_NODE1),
		.evirt = __phys_to_virt(CONFIG_CXD4105_PHYS_OFFSET_NODE1 + CONFIG_CXD4105_SIZE_NODE1),
	}
};

static inline unsigned long __pfn_to_nid(unsigned long pfn)
{
	if (pfn >= cxd4105_nodeinfo[0].spfn && pfn < cxd4105_nodeinfo[0].epfn)
		return 0;
	else if (pfn >= cxd4105_nodeinfo[1].spfn && pfn < cxd4105_nodeinfo[1].epfn)
		return 1;
	else
		return -1UL;
}

static inline unsigned long __kaddr_to_nid(unsigned long kaddr)
{
	if (kaddr >= cxd4105_nodeinfo[0].svirt && kaddr < cxd4105_nodeinfo[0].evirt)
		return 0;
	else if (kaddr >= cxd4105_nodeinfo[1].svirt && kaddr < cxd4105_nodeinfo[1].evirt)
		return 1;
	else
		return -1UL;
}

static inline unsigned long __local_map_nr(unsigned long kaddr)
{
	unsigned long pfn = __virt_to_phys(kaddr) >> PAGE_SHIFT;
	return pfn - cxd4105_nodeinfo[PFN_TO_NID(pfn)].spfn;
}
#endif /* __ASSEMBLY__ */

#elif defined(CONFIG_NUMA)

#define PFN_TO_NID(pfn)         pfn_to_nid(pfn)

#else

#define PFN_TO_NID(addr)	(0)

#endif

#ifdef CONFIG_ARCH_POPULATES_NODE_MAP
# ifdef CONFIG_HAVE_ARCH_EARLY_PFN_TO_NID
#  ifndef __ASSEMBLY__
extern int early_pfn_to_nid(unsigned long pfn);
#  endif /* !__ASSEMBLY__ */
# endif /* CONFIG_HAVE_ARCH_EARLY_PFN_TO_NID */
#define EARLY_PFN_TO_NID(pfn)	early_pfn_to_nid(pfn)
#else
#define EARLY_PFN_TO_NID(pfn)	PFN_TO_NID(pfn)
#endif /* CONFIG_ARCH_POPULATES_NODE_MAP */

#endif
