summaryrefslogtreecommitdiffstats
path: root/firmware/target/arm/as3525/dbop-as3525.c
blob: 1816b5205b5f84a860b92783117b583a9bfffa5b (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
133
134
135
136
137
138
139
140
141
142
143
144
/***************************************************************************
 *             __________               __   ___.
 *   Open      \______   \ ____   ____ |  | _\_ |__   _______  ___
 *   Source     |       _//  _ \_/ ___\|  |/ /| __ \ /  _ \  \/  /
 *   Jukebox    |    |   (  <_> )  \___|    < | \_\ (  <_> > <  <
 *   Firmware   |____|_  /\____/ \___  >__|_ \|___  /\____/__/\_ \
 *                     \/            \/     \/    \/            \/
 * $Id$
 *
 * Copyright (C) 2009 by Bertrik Sikken
 *
 * 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 software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
 * KIND, either express or implied.
 *
 ****************************************************************************/

#include "config.h"
#include <inttypes.h>
#include "as3525.h"
#include "dbop-as3525.h"

#if defined(SANSA_FUZE) || defined(SANSA_FUZEV2)
#define DBOP_PRECHARGE 0x80FF
#elif defined(SANSA_E200V2) || defined(SANSA_C200V2)
#define DBOP_PRECHARGE 0xF0FF
#endif

#if CONFIG_CPU == AS3525
/* doesn't work with the new ams sansas so far and is not needed */
static short int dbop_input_value = 0;

/* read the DBOP data pins */
unsigned short dbop_read_input(void)
{
    unsigned int dbop_ctrl_old = DBOP_CTRL;
    unsigned int dbop_timpol23_old = DBOP_TIMPOL_23;

    /* make sure that the DBOP FIFO is empty */
    while ((DBOP_STAT & (1<<10)) == 0);

    int delay = 10;
    while (delay--) asm volatile ("nop\n");

    /* write DBOP_DOUT to pre-charge DBOP data lines with a defined level */
    DBOP_TIMPOL_23 = 0xe007e007;    /* no strobe towards lcd */
    DBOP_CTRL = (1 << 19) |         /* tri-state output */
                (1 << 16) |         /* enw=1 (enable write) */
                (1 << 12);          /* ow=1 (16-bit data width) */
    DBOP_DOUT = DBOP_PRECHARGE;
#if defined(SANSA_C200V2)
    /* two additional writes to precharge longer get rid of the read noise */
    DBOP_DOUT = DBOP_PRECHARGE;
    DBOP_DOUT = DBOP_PRECHARGE;
#endif
    while ((DBOP_STAT & (1<<10)) == 0);

#if defined(SANSA_FUZE) || defined(SANSA_E200V2)
    delay = 50;
    while (delay--) asm volatile ("nop\n");
#endif

    /* perform a DBOP read */
    DBOP_CTRL = (1 << 19) |         /* tri-state output */
                (1 << 15) |         /* strd=1 (start read) */
                (1 << 12) |         /* ow=1 (16-bit data width) */
                (31 << 0);          /* rs_t=31 (read DBOP at end of cycle) */
    while ((DBOP_STAT & (1<<16)) == 0);
    dbop_input_value = DBOP_DIN;

    /* restore previous values */
    DBOP_TIMPOL_23 = dbop_timpol23_old;
    DBOP_CTRL = dbop_ctrl_old;

    return dbop_input_value;
}

/* for the debug menu */
unsigned short dbop_debug(void)
{
    return dbop_input_value;
}

#endif

static inline void dbop_set_mode(int mode)
{
    int delay = 10;
    unsigned long ctrl = DBOP_CTRL;
    int curr_mode = (DBOP_CTRL >> 13) & 0x3; // bits 14:13
#ifdef SANSA_FUZEV2
    if (mode == 32 && curr_mode != 1<<1)
        DBOP_CTRL = (ctrl & ~(1<<13)) | (1<<14); // 2 serial half words
    else if (mode == 16 && curr_mode != 1<<0)
        DBOP_CTRL = (ctrl & ~(1<<14)) | (1<<13); // 2 serial bytes
#else
    if (mode == 32 && curr_mode == 0)
        DBOP_CTRL = ctrl | (1<<13|1<<14); /* 2 serial half words */
    else if (mode == 16 && curr_mode == (1<<1|1<<0))
        DBOP_CTRL =  ctrl & ~(1<<14|1<<13); /* 1 serial half word */
#endif
    else
        return;
    while(delay--) asm volatile("nop");
}

void dbop_write_data(const int16_t* p_bytes, int count)
{
    
    const int32_t *data;
    if ((intptr_t)p_bytes & 0x3 || count == 1)
    {   /* need to do a single 16bit write beforehand if the address is
         * not word aligned or count is 1, switch to 16bit mode if needed */
        dbop_set_mode(16);
        DBOP_DOUT16 = *p_bytes++;
        if (!(--count))
            return;
    }
    /* from here, 32bit transfers are save
     * set it to transfer 4*(outputwidth) units at a time,
     * if bit 12 is set it only does 2 halfwords though (we never set it)
     * switch to 32bit output if needed */
    dbop_set_mode(32);
    data = (int32_t*)p_bytes;
    while (count > 1)
    {
        DBOP_DOUT32 = *data++;
        count -= 2;

        /* Wait if push fifo is full */
        while ((DBOP_STAT & (1<<6)) != 0);
    }
    /* While push fifo is not empty */
    while ((DBOP_STAT & (1<<10)) == 0);

    /* due to the 32bit alignment requirement or uneven count,
     * we possibly need to do a 16bit transfer at the end also */
    if (count > 0)
        dbop_write_data((int16_t*)data, 1);
}