aboutsummaryrefslogtreecommitdiff
path: root/README.md
blob: 570080d03a8e5926982ca95577a590ecd3aa4094 (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
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
# CDS9K Linux Kernel Drivers

This repo houses Linux kernel drivers for the CDS9K FPGA/CPLD.

This is a semi-fictional piece of hardware I'm developing for classroom/demo
sessions on various aspects of Linux kernel driver development - it's not on
any real boards, it's just a teaching tool. I do have a VHDL implementation
which I will include once the IP blocks are more stable.

Unless otherwise noted, for all reserved bits in registers, read as "don't
care" and write as 0.

## IP Block: `cds9k-fan`

The CDS9K fan control block allows PWM speed control of a single fan, and
readback of the fan's tachometer.

### Register 0x0: FAN\_PWM

Mode: read-write

Write this register to set the fan PWM duty.

| Bits | 15 - 8   | 7 - 0     |
| ---- | -------- | --------- |
| Use  | reserved | duty\_val |

The value for `duty_val` can be determined as:

	duty_val = duty_percent * 2.55

i.e. a linear scaling from 0-100% to 0x0-0xFF

### Register 0x1: FAN\_TACH

Mode: read-only

Read this register to determine the fan tachometer reading in revolutions per
minute (RPM).

| Bits | 15 - 0   |
| ---- | -------- |
| Use  | fan\_rpm |


## IP Block: `cds9k-led`

The CDS9K LED control block allows PWM brightness control of a single LED (or
LED die, in the case of multi-colour LEDs) as well as hardware-accelerated
blinking with 50% duty and variable period.

Two signals are generated internally: blink and PWM. These are ANDed together
to form the LED output. A sample waveform diagram (relative timings not to
scale):

	blink   ----------------                ----------------                -
	                        ----------------                ----------------
	PWM     -    -    -    -    -    -    -    -    -    -    -    -    -
	         ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ----
	led     -    -    -    -                   -    -    -
	drive    ---- ---- ---- ------------------- ---- ---- -------------------

The `blink` signal has a fixed duty of 50% and a period programmable between
20 milliseconds and 5.1 seconds. The PWM signal has a fixed period of 40
microseconds (i.e. 25 kHz), and a duty programmable between 0 and 100%.

### Register 0x0: LED\_PWM\_DUTY

Mode: read-write

Write this register to set the LED PWM duty. The PWM duty can be calculated as:

| Bits | 15 - 8   | 7 - 0     |
| ---- | -------- | --------- |
| Use  | reserved | duty\_val |

The value for `duty_val` can be determined as:

	duty_val = duty_percent * 2.55

i.e. a linear scaling from 0-100% to 0x0-0xFF

### Register 0x0: LED\_BLINK\_PERIOD

Mode: read-write

Write this register to set the LED blink period. When a non-zero value is
written to this register, the LED output is gated by a 50% duty square wave
with period:

	period_val = 20 milliseconds * LED_BLINK_PERIOD

In this way, the LED can be blinked on and off with 50% duty at a programmable
frequency. When the LED should be enabled during each cycle, it is driven at
the PWM brightness programmed in the `LED_PWM_DUTY` register.

| Bits | 15 - 8   | 7 - 0       |
| ---- | -------- | ----------- |
| Use  | reserved | period\_val |


## IP Block: `cds9k-gpio`

The CDS9K GPIO block provides access to 16 basic I/O lines. Interrupts and
pull-ups/pull-downs are not available. GPIO lines are individually selectable
between input/hi-z and output.

### Register: 0x0: PORT

Mode: read-write

| Bits | 15 - 0 |
| ---- | ------ |
| Use  | port   |

### Register: 0x1: DIRECTION

Mode: read-write

| Bits | 15 - 0          |
| ---- | --------------- |
| Use  | direction\_mask |


## IP Block: `cds9k-reset`

The CDS9K reset control block exposes a single reset line which can be asserted
and deasserted by writing different magic values to a single 16-bit register.

### Register: 0x0: REG0

Mode: read-write

Write as 0xDEAD to assert the reset, and write as 0x0000 to deassert the reset.

| Bits | 15 - 0       |
| ---- | ------------ |
| Use  | reset\_magic |

### Register: 0x1: RESERVED

Mode: read-only

Write as 0xDEAD to assert the reset, and write as 0x0000 to deassert the reset.

| Bits | 15 - 0   |
| ---- | -------- |
| Use  | reserved |


## Misc drivers

There is currently one misc driver in this repo too: `simple-reset-consumer`.
On probe, this driver takes a single reset from the device-tree and asks it to
reset. This is the quickest way I had for hackily debugging the effect of a
reset driver such as cds9k-reset, as there doesn't appear to be any sysfs or
debugfs nodes exposed for reset controllers in general.

If you include a segment in your device tree like:

	some_reset_consumer {
		compatible = "david,simple-reset-consumer";
		resets = <&some_reset>;
		status = "okay";
	};

Then firing the resets looks like:

	root@de10-nano:~# rmmod simple-reset-consumer
	root@de10-nano:~# modprobe simple-reset-consumer
	[  995.241046] simple-reset-consumer some_reset_consumer: firing reset
	root@de10-nano:~#