summaryrefslogtreecommitdiff
path: root/arch/arm/mach-omap2/emif_omap.c
blob: 4c59e61bd706eb50311991005577883c767003fc (plain)
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
/*
 * EMIF devices creation for OMAP4+
 *
 * Copyright (C) 2010 Texas Instruments, Inc.
 *
 * Aneesh V <aneesh@ti.com>
 * Santosh Shilimkar <santosh.shilimkar@ti.com>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 as
 * published by the Free Software Foundation.
 */
#include <linux/kernel.h>
#include <linux/clk.h>
#include <linux/init.h>
#include <linux/emif.h>
#include <plat/omap_hwmod.h>
#include <plat/omap_device.h>
#include "common.h"

static struct omap_device_pm_latency omap_emif_latency[] = {
	[0] = {
		.deactivate_func = omap_device_idle_hwmods,
		.activate_func = omap_device_enable_hwmods,
		.flags = OMAP_DEVICE_LATENCY_AUTO_ADJUST,
	}
};

static struct emif_platform_data omap_emif_platform_data __initdata = {
	.hw_caps = EMIF_HW_CAPS_LL_INTERFACE
};

/**
 * omap4_emif_set_device_details() - Pass DDR device details from board file
 * @emif_nr:		The EMIF instance on which device is attached
 * @device_info:	Device info such as type, bus width, density etc.
 * @timings:		Timings information from device datasheet passed
 *			as an array of 'struct lpddr2_timings'. Can be NULL
 *			if if default timings are ok.
 * @timings_arr_size:	Size of the timings array. Depends on the number
 *			of different frequencies for which timings data
 *			is provided.
 * @min_tck:		Minimum value of some timing parameters in terms
 *			of number of cycles. Can be NULL if default values
 *			are ok.
 *
 * This function shall be used by the OMAP board files to pass DDR device
 * device information to the EMIF driver. It will in turn create EMIF
 * platform devices and pass the DDR device data and HW capability information
 * to the EMIF driver through platform data.
 */
void __init omap_emif_set_device_details(u32 emif_nr,
			struct ddr_device_info *device_info,
			struct lpddr2_timings *timings,
			u32 timings_arr_size,
			struct ddr_min_tck *min_tck,
			struct emif_custom_configs *custom_configs)
{
	struct platform_device	*pd;
	struct omap_hwmod	*oh;
	char			oh_name[10];

	if (emif_nr > 2 || !device_info)
		goto error;

	if (cpu_is_omap44xx()) {
		omap_emif_platform_data.ip_rev = EMIF_4D;
		omap_emif_platform_data.phy_type = EMIF_PHY_TYPE_ATTILAPHY;
	} else if (cpu_is_omap54xx()) {
		omap_emif_platform_data.ip_rev = EMIF_4D5;
		omap_emif_platform_data.phy_type = EMIF_PHY_TYPE_INTELLIPHY;
	} else {
		goto error;
	}

	sprintf(oh_name, "emif%d", emif_nr);

	oh = omap_hwmod_lookup(oh_name);
	if (!oh) {
		pr_err("EMIF: could not find hwmod for %s\n", oh_name);
		return;
	}

	omap_emif_platform_data.device_info = device_info;
	omap_emif_platform_data.timings = timings;
	omap_emif_platform_data.min_tck = min_tck;
	omap_emif_platform_data.timings_arr_size = timings_arr_size;
	omap_emif_platform_data.custom_configs = custom_configs;

	oh = omap_hwmod_lookup(oh_name);
	if (!oh)
		goto error;

	pd = omap_device_build("emif", emif_nr, oh,
				&omap_emif_platform_data,
				sizeof(omap_emif_platform_data),
				omap_emif_latency,
				ARRAY_SIZE(omap_emif_latency), false);
	if (!pd)
		goto error;

	return;
error:
	pr_err("OMAP: EMIF device generation failed for EMIF%u\n", emif_nr);
	return;
}

/*
 * Reconfigure EMIF timing registers to known values by doing a setrate
 * at the current frequency that will in turn invoke EMIF driver APIs
 */
static int __init init_emif_timings(void)
{
	struct clk	*dpll_core_m2_clk;
	u32		rate;

	dpll_core_m2_clk = clk_get(NULL, "dpll_core_m2_ck");
	if (!dpll_core_m2_clk)
		goto error;

	rate = clk_get_rate(dpll_core_m2_clk);

	pr_info("Reprogramming LPDDR2 timings to %d Hz\n", rate);
	if (clk_set_rate(dpll_core_m2_clk, rate))
		goto error;

	return 0;
error:
	pr_err("init_emif_timings failed\n");
	return -1;
}
device_initcall(init_emif_timings);