Repository navigation
Expand file tree
/
Copy pathSpiPanelIO.cpp
More file actions
125 lines (114 loc) · 2.83 KB
/
Copy pathSpiPanelIO.cpp
File metadata and controls
125 lines (114 loc) · 2.83 KB
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
#include "SpiPanelIO.h"
namespace DekiDisplay
{
bool SpiPanelIO::Begin()
{
if (!m_Device || !m_Device->Acquire())
{
return false;
}
++m_Depth;
return true;
}
void SpiPanelIO::End()
{
if (m_Depth == 0)
{
return;
}
// Only the outermost End waits: a Begin inside a held run (a strip inside
// the worker's run of strips) leaves what it queued on the wire.
if (--m_Depth == 0)
{
m_Device->Wait(0);
}
m_Device->Release();
}
bool SpiPanelIO::Queue(const DekiSpi::Transfer& t)
{
if (!m_Device->Queue(t))
{
return false;
}
++m_Queued;
return true;
}
bool SpiPanelIO::Command(uint8_t cmd, const uint8_t* params, size_t n)
{
// Inside a run, behind the pixels before it: the device copies a transfer
// of four bytes or less, so neither needs to outlive this call.
const bool queue = m_Depth > 0 && n <= 4;
if (!Begin())
{
return false;
}
// Chip select stays low from the command byte into its parameters.
DekiSpi::Transfer c;
c.tx = &cmd;
c.txBytes = 1;
c.dc = 0;
c.keepCs = n > 0;
bool ok = queue ? Queue(c) : m_Device->Transmit(c);
if (ok && n > 0)
{
DekiSpi::Transfer p;
p.tx = params;
p.txBytes = n;
p.dc = 1;
ok = queue ? Queue(p) : m_Device->Transmit(p);
}
End();
return ok;
}
bool SpiPanelIO::StartPixels(uint8_t memoryWriteCmd)
{
if (!m_Device)
{
return false;
}
// Inside a Begin the command is queued, and keeps chip select low into
// the pixels that follow it. Outside one there is no bus to hold, and the
// panel takes the pixels after chip select has gone high and low again,
// as a MIPI DBI controller does until the next command.
DekiSpi::Transfer c;
c.tx = &memoryWriteCmd;
c.txBytes = 1;
c.dc = 0;
c.keepCs = m_Depth > 0;
return m_Depth > 0 ? Queue(c) : m_Device->Transmit(c);
}
bool SpiPanelIO::QueuePixels(const void* data, size_t bytes, bool more)
{
if (!m_Device || bytes == 0)
{
return bytes == 0;
}
DekiSpi::Transfer t;
t.tx = data;
t.txBytes = bytes;
t.dc = 1;
t.keepCs = more && m_Depth > 0;
return Queue(t);
}
bool SpiPanelIO::WaitPixels(size_t leaveInFlight)
{
return m_Device && m_Device->Wait(leaveInFlight);
}
size_t SpiPanelIO::GetMaxChunkBytes() const
{
return m_Device ? m_Device->GetMaxTransferBytes() : 0;
}
bool SpiPanelIO::Read(uint8_t cmd, uint8_t* out, size_t n)
{
// One transfer, the command as its command phase: a device read at a
// clock of its own reads through a second driver handle, and the whole
// read is on it.
DekiSpi::Transfer r;
r.cmdBits = 8;
r.cmd = cmd;
r.rx = out;
r.rxBytes = n;
r.dc = 0;
return m_Device->Transmit(r);
}
} // namespace DekiDisplay