aboutsummaryrefslogtreecommitdiffstats
path: root/arch/mips/powertv/ioremap.c
blob: a77c6f62fe238ccf4e33c6b6784865c2d3a7d2a6 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
/*
 *			ioremap.c
 *
 * Support for mapping between dma_addr_t values a phys_addr_t values.
 *
 * Copyright (C) 2005-2009 Scientific-Atlanta, Inc.
 *
 * 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
 *
 * Author:       David VomLehn <dvomlehn@cisco.com>
 *
 * Description:  Defines the platform resources for the SA settop.
 *
 * NOTE: The bootloader allocates persistent memory at an address which is
 * 16 MiB below the end of the highest address in KSEG0. All fixed
 * address memory reservations must avoid this region.
 */

#include <linux/kernel.h>
#include <linux/module.h>

#include <asm/mach-powertv/ioremap.h>

/*
 * Define the sizes of and masks for grains in physical and DMA space. The
 * values are the same but the types are not.
 */
#define IOR_PHYS_GRAIN		((phys_addr_t) 1 << IOR_LSBITS)
#define IOR_PHYS_GRAIN_MASK	(IOR_PHYS_GRAIN - 1)

#define IOR_DMA_GRAIN		((dma_addr_t) 1 << IOR_LSBITS)
#define IOR_DMA_GRAIN_MASK	(IOR_DMA_GRAIN - 1)

/*
 * Values that, when accessed by an index derived from a phys_addr_t and
 * added to phys_addr_t value, yield a DMA address
 */
struct ior_phys_to_dma _ior_phys_to_dma[IOR_NUM_PHYS_TO_DMA];
EXPORT_SYMBOL(_ior_phys_to_dma);

/*
 * Values that, when accessed by an index derived from a dma_addr_t and
 * added to that dma_addr_t value, yield a physical address
 */
struct ior_dma_to_phys _ior_dma_to_phys[IOR_NUM_DMA_TO_PHYS];
EXPORT_SYMBOL(_ior_dma_to_phys);

/**
 * setup_dma_to_phys - set up conversion from DMA to physical addresses
 * @dma_idx:	Top IOR_LSBITS bits of the DMA address, i.e. an index
 *		into the array _dma_to_phys.
 * @delta:	Value that, when added to the DMA address, will yield the
 *		physical address
 * @s:		Number of bytes in the section of memory with the given delta
 *		between DMA and physical addresses.
 */
static void setup_dma_to_phys(dma_addr_t dma, phys_addr_t delta, dma_addr_t s)
{
	int dma_idx, first_idx, last_idx;
	phys_addr_t first, last;

	/*
	 * Calculate the first and last indices, rounding the first up and
	 * the second down.
	 */
	first = dma & ~IOR_DMA_GRAIN_MASK;
	last = (dma + s - 1) & ~IOR_DMA_GRAIN_MASK;
	first_idx = first >> IOR_LSBITS;		/* Convert to indices */
	last_idx = last >> IOR_LSBITS;

	for (dma_idx = first_idx; dma_idx <= last_idx; dma_idx++)
		_ior_dma_to_phys[dma_idx].offset = delta >> IOR_DMA_SHIFT;
}

/**
 * setup_phys_to_dma - set up conversion from DMA to physical addresses
 * @phys_idx:	Top IOR_LSBITS bits of the DMA address, i.e. an index
 *		into the array _phys_to_dma.
 * @delta:	Value that, when added to the DMA address, will yield the
 *		physical address
 * @s:		Number of bytes in the section of memory with the given delta
 *		between DMA and physical addresses.
 */
static void setup_phys_to_dma(phys_addr_t phys, dma_addr_t delta, phys_addr_t s)
{
	int phys_idx, first_idx, last_idx;
	phys_addr_t first, last;

	/*
	 * Calculate the first and last indices, rounding the first up and
	 * the second down.
	 */
	first = phys & ~IOR_PHYS_GRAIN_MASK;
	last = (phys + s - 1) & ~IOR_PHYS_GRAIN_MASK;
	first_idx = first >> IOR_LSBITS;		/* Convert to indices */
	last_idx = last >> IOR_LSBITS;

	for (phys_idx = first_idx; phys_idx <= last_idx; phys_idx++)
		_ior_phys_to_dma[phys_idx].offset = delta >> IOR_PHYS_SHIFT;
}

/**
 * ioremap_add_map - add to the physical and DMA address conversion arrays
 * @phys:	Process's view of the address of the start of the memory chunk
 * @dma:	DMA address of the start of the memory chunk
 * @size:	Size, in bytes, of the chunk of memory
 *
 * NOTE: It might be obvious, but the assumption is that all @size bytes have
 * the same offset between the physical address and the DMA address.
 */
void ioremap_add_map(phys_addr_t phys, phys_addr_t dma, phys_addr_t size)
{
	if (size == 0)
		return;

	if ((dma & IOR_DMA_GRAIN_MASK) != 0 ||
		(phys & IOR_PHYS_GRAIN_MASK) != 0 ||
		(size & IOR_PHYS_GRAIN_MASK) != 0)
		pr_crit("Memory allocation must be in chunks of 0x%x bytes\n",
			IOR_PHYS_GRAIN);

	setup_dma_to_phys(dma, phys - dma, size);
	setup_phys_to_dma(phys, dma - phys, size);
}