Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
awilliam
GitHub Repository: awilliam/linux-vfio
Path: blob/master/arch/arm/mach-davinci/aemif.c
10699 views
1
/*
2
* AEMIF support for DaVinci SoCs
3
*
4
* Copyright (C) 2010 Texas Instruments Incorporated. http://www.ti.com/
5
*
6
* This program is free software; you can redistribute it and/or modify
7
* it under the terms of the GNU General Public License version 2 as
8
* published by the Free Software Foundation.
9
*/
10
11
#include <linux/kernel.h>
12
#include <linux/io.h>
13
#include <linux/err.h>
14
#include <linux/clk.h>
15
#include <linux/module.h>
16
#include <linux/time.h>
17
18
#include <mach/aemif.h>
19
20
/* Timing value configuration */
21
22
#define TA(x) ((x) << 2)
23
#define RHOLD(x) ((x) << 4)
24
#define RSTROBE(x) ((x) << 7)
25
#define RSETUP(x) ((x) << 13)
26
#define WHOLD(x) ((x) << 17)
27
#define WSTROBE(x) ((x) << 20)
28
#define WSETUP(x) ((x) << 26)
29
30
#define TA_MAX 0x3
31
#define RHOLD_MAX 0x7
32
#define RSTROBE_MAX 0x3f
33
#define RSETUP_MAX 0xf
34
#define WHOLD_MAX 0x7
35
#define WSTROBE_MAX 0x3f
36
#define WSETUP_MAX 0xf
37
38
#define TIMING_MASK (TA(TA_MAX) | \
39
RHOLD(RHOLD_MAX) | \
40
RSTROBE(RSTROBE_MAX) | \
41
RSETUP(RSETUP_MAX) | \
42
WHOLD(WHOLD_MAX) | \
43
WSTROBE(WSTROBE_MAX) | \
44
WSETUP(WSETUP_MAX))
45
46
/*
47
* aemif_calc_rate - calculate timing data.
48
* @wanted: The cycle time needed in nanoseconds.
49
* @clk: The input clock rate in kHz.
50
* @max: The maximum divider value that can be programmed.
51
*
52
* On success, returns the calculated timing value minus 1 for easy
53
* programming into AEMIF timing registers, else negative errno.
54
*/
55
static int aemif_calc_rate(int wanted, unsigned long clk, int max)
56
{
57
int result;
58
59
result = DIV_ROUND_UP((wanted * clk), NSEC_PER_MSEC) - 1;
60
61
pr_debug("%s: result %d from %ld, %d\n", __func__, result, clk, wanted);
62
63
/* It is generally OK to have a more relaxed timing than requested... */
64
if (result < 0)
65
result = 0;
66
67
/* ... But configuring tighter timings is not an option. */
68
else if (result > max)
69
result = -EINVAL;
70
71
return result;
72
}
73
74
/**
75
* davinci_aemif_setup_timing - setup timing values for a given AEMIF interface
76
* @t: timing values to be progammed
77
* @base: The virtual base address of the AEMIF interface
78
* @cs: chip-select to program the timing values for
79
*
80
* This function programs the given timing values (in real clock) into the
81
* AEMIF registers taking the AEMIF clock into account.
82
*
83
* This function does not use any locking while programming the AEMIF
84
* because it is expected that there is only one user of a given
85
* chip-select.
86
*
87
* Returns 0 on success, else negative errno.
88
*/
89
int davinci_aemif_setup_timing(struct davinci_aemif_timing *t,
90
void __iomem *base, unsigned cs)
91
{
92
unsigned set, val;
93
int ta, rhold, rstrobe, rsetup, whold, wstrobe, wsetup;
94
unsigned offset = A1CR_OFFSET + cs * 4;
95
struct clk *aemif_clk;
96
unsigned long clkrate;
97
98
if (!t)
99
return 0; /* Nothing to do */
100
101
aemif_clk = clk_get(NULL, "aemif");
102
if (IS_ERR(aemif_clk))
103
return PTR_ERR(aemif_clk);
104
105
clkrate = clk_get_rate(aemif_clk);
106
107
clkrate /= 1000; /* turn clock into kHz for ease of use */
108
109
ta = aemif_calc_rate(t->ta, clkrate, TA_MAX);
110
rhold = aemif_calc_rate(t->rhold, clkrate, RHOLD_MAX);
111
rstrobe = aemif_calc_rate(t->rstrobe, clkrate, RSTROBE_MAX);
112
rsetup = aemif_calc_rate(t->rsetup, clkrate, RSETUP_MAX);
113
whold = aemif_calc_rate(t->whold, clkrate, WHOLD_MAX);
114
wstrobe = aemif_calc_rate(t->wstrobe, clkrate, WSTROBE_MAX);
115
wsetup = aemif_calc_rate(t->wsetup, clkrate, WSETUP_MAX);
116
117
if (ta < 0 || rhold < 0 || rstrobe < 0 || rsetup < 0 ||
118
whold < 0 || wstrobe < 0 || wsetup < 0) {
119
pr_err("%s: cannot get suitable timings\n", __func__);
120
return -EINVAL;
121
}
122
123
set = TA(ta) | RHOLD(rhold) | RSTROBE(rstrobe) | RSETUP(rsetup) |
124
WHOLD(whold) | WSTROBE(wstrobe) | WSETUP(wsetup);
125
126
val = __raw_readl(base + offset);
127
val &= ~TIMING_MASK;
128
val |= set;
129
__raw_writel(val, base + offset);
130
131
return 0;
132
}
133
EXPORT_SYMBOL(davinci_aemif_setup_timing);
134
135