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
137
138
139
140
141
142
143
144
145
146
|
/*
* Freescale iMX51 ATA driver
*
* Copyright (C) 2010 Marek Vasut <marek.vasut@gmail.com>
*
* Based on code by:
* Mahesh Mahadevan <mahesh.mahadevan@freescale.com>
*
* Based on code from original FSL ATA driver, which is
* part of eCos, the Embedded Configurable Operating System.
* Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, 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., 59 Temple Place, Suite 330, Boston,
* MA 02111-1307 USA
*/
#include <common.h>
#include <command.h>
#include <config.h>
#include <asm/byteorder.h>
#include <asm/io.h>
#include <ide.h>
#include <asm/arch/imx-regs.h>
#include <asm/arch/clock.h>
/* MXC ATA register offsets */
struct mxc_ata_config_regs {
u8 time_off; /* 0x00 */
u8 time_on;
u8 time_1;
u8 time_2w;
u8 time_2r;
u8 time_ax;
u8 time_pio_rdx;
u8 time_4;
u8 time_9;
u8 time_m;
u8 time_jn;
u8 time_d;
u8 time_k;
u8 time_ack;
u8 time_env;
u8 time_udma_rdx;
u8 time_zah; /* 0x10 */
u8 time_mlix;
u8 time_dvh;
u8 time_dzfs;
u8 time_dvs;
u8 time_cvh;
u8 time_ss;
u8 time_cyc;
u32 fifo_data_32; /* 0x18 */
u32 fifo_data_16;
u32 fifo_fill;
u32 ata_control;
u32 interrupt_pending;
u32 interrupt_enable;
u32 interrupt_clear;
u32 fifo_alarm;
};
struct mxc_data_hdd_regs {
u32 drive_data; /* 0xa0 */
u32 drive_features;
u32 drive_sector_count;
u32 drive_sector_num;
u32 drive_cyl_low;
u32 drive_cyl_high;
u32 drive_dev_head;
u32 command;
u32 status;
u32 alt_status;
};
/* PIO timing table */
#define NR_PIO_SPECS 5
static uint16_t pio_t1[NR_PIO_SPECS] = { 70, 50, 30, 30, 25 };
static uint16_t pio_t2_8[NR_PIO_SPECS] = { 290, 290, 290, 80, 70 };
static uint16_t pio_t4[NR_PIO_SPECS] = { 30, 20, 15, 10, 10 };
static uint16_t pio_t9[NR_PIO_SPECS] = { 20, 15, 10, 10, 10 };
static uint16_t pio_tA[NR_PIO_SPECS] = { 50, 50, 50, 50, 50 };
#define REG2OFF(reg) ((((uint32_t)reg) & 0x3) * 8)
static void set_ata_bus_timing(unsigned char mode)
{
uint32_t val;
uint32_t T = 1000000000 / mxc_get_clock(MXC_IPG_CLK);
struct mxc_ata_config_regs *ata_regs;
ata_regs = (struct mxc_ata_config_regs *)CONFIG_SYS_ATA_BASE_ADDR;
if (mode >= NR_PIO_SPECS)
return;
/* Write TIME_OFF/ON/1/2W */
val = (3 << REG2OFF(&ata_regs->time_off)) |
(3 << REG2OFF(&ata_regs->time_on)) |
(((pio_t1[mode] + T) / T) << REG2OFF(&ata_regs->time_1)) |
(((pio_t2_8[mode] + T) / T) << REG2OFF(&ata_regs->time_2w));
writel(val, &ata_regs->time_off);
/* Write TIME_2R/AX/RDX/4 */
val = (((pio_t2_8[mode] + T) / T) << REG2OFF(&ata_regs->time_2r)) |
(((pio_tA[mode] + T) / T + 2) << REG2OFF(&ata_regs->time_ax)) |
(1 << REG2OFF(&ata_regs->time_pio_rdx)) |
(((pio_t4[mode] + T) / T) << REG2OFF(&ata_regs->time_4));
writel(val, &ata_regs->time_2r);
/* Write TIME_9 ; the rest of timing registers is irrelevant for PIO */
val = (((pio_t9[mode] + T) / T) << REG2OFF(&ata_regs->time_9));
writel(val, &ata_regs->time_9);
}
int ide_preinit(void)
{
struct mxc_ata_config_regs *ata_regs;
ata_regs = (struct mxc_ata_config_regs *)CONFIG_SYS_ATA_BASE_ADDR;
/* 46.3.3.4 @ FSL iMX51 manual */
/* FIFO normal op., drive reset */
writel(0x80, &ata_regs->ata_control);
/* FIFO normal op., drive not reset */
writel(0xc0, &ata_regs->ata_control);
/* Configure the PIO timing */
set_ata_bus_timing(CONFIG_MXC_ATA_PIO_MODE);
/* 46.3.3.4 @ FSL iMX51 manual */
/* Drive not reset, IORDY handshake */
writel(0x41, &ata_regs->ata_control);
return 0;
}
|