Commit ce1cae21 authored by Alessandro Rubini's avatar Alessandro Rubini

kernel,user,doc: added mode-setting for the channels

Signed-off-by: Alessandro Rubini's avatarAlessandro Rubini <rubini@gnudd.com>
parent f7422fd0
......@@ -621,7 +621,12 @@ generated a MAC address using the serial number of the internal
thermometer.
The user is thus only expected to assign an Internet address to the
Ethernet port and just use it to transfer data.
Ethernet port and just use it to transfer data. If you need to change
the MAC address, the command you need is something like the following:
@example
ifconfig wr0 hw ether 12:34:56:78:9a:bc
@end example
The port supports hardware timestamping for user frames through the
standard Linux mechanisms, but at this point no sample code is provided
......@@ -779,8 +784,44 @@ The current version of the tool supports the following commands:
is not modified. The @code{+} form is useful for simple checks with
visual inspection.
@item mode <channel> <mode> [<channel> <mode> ...]
@itemx mode <mode0><mode1><mode2><mode3><mode4>
Configure one or more channel for the specified mode. Each mode
is one character, so the second form receives a 5-byte
string argument. Available modes are ``@code{I}'' (input),
``@code{0}'' and ``@code{1}'' (output, steady state),
``@code{D}'' (DIO core output) or ``@code{-}'' (unchanged).
A channel managed by the DIO core is normally low and can
pulse high on request (see @code{pulse}
command. Uppercase @code{D} or @code{I} select the termination
resistor, while lowercase @code{d} or @code{i} disable the termination
(output is always without termination, but I may add @code{L} and
@code{H} if needed: the driver supports all combinations).
Please note that the @code{pulse} command turns the affected channel in
@i{DIO} mode anyways (without changing the termination).
@end table
Example uses of the tool follow:
@example
# Pulse channel 4 for 0.1 seconds now
wr-dio-cmd wr0 pulse 4 .1 now
# Pulse for 10 microseconds in the middle of the next second
wr-dio-cmd wr0 pulse 4 .00001 +1.5
# Pulse for 1ms at 17:00 today
wr-dio-cmd wr0 pulse 4 .001 $(date +%s --date 17:00)
# Get timestamps for the output events above
wr-dio-cmd wr0 stamp 4
# Configure channel 0 as input with termination, 1 as input, 4 as low
wr-dio-cmd wr0 mode Ii--0
@end example
@c ==========================================================================
@node The Future of WR-NIC
@section The Future of WR-NIC
......
......@@ -56,9 +56,14 @@ enum wr_dio_cmd_name {
* CMD_INOUT:
* cmd->flags: F_MASK
* cmd->channel: the channel or the mask
* cmd->value: bits 0..4: data, bits 8..12 OEN (high active), 16..20 term
* cmd->value: bits 0..4: WR-DIO, 8..12 value, 16..20 OEN, 24..28 term
*/
#define WR_DIO_INOUT_DIO (1 << 0)
#define WR_DIO_INOUT_VALUE (1 << 8)
#define WR_DIO_INOUT_OUTPUT (1 << 16)
#define WR_DIO_INOUT_TERM (1 << 24)
#define WR_DIO_N_STAMP 16 /* At least 5 * 3 */
struct wr_dio_cmd {
......
......@@ -102,15 +102,15 @@ static int wrn_dio_cmd_pulse(struct wrn_drvdata *drvdata,
struct PPSG_WB __iomem *ppsg = drvdata->ppsg_base;
struct regmap *map;
struct timespec *ts;
uint32_t val;
uint32_t reg;
if (cmd->channel > 4)
return -EINVAL; /* FIXME: mask */
map = regmap + cmd->channel;
/* First, put this bit as output (FIXME: plain GPIO support?) */
val = readl(&dio->OUT) | (1 << cmd->channel);
writel(val, &dio->OUT);
reg = readl(&dio->OUT) | (1 << cmd->channel);
writel(reg, &dio->OUT);
ts = cmd->t;
......@@ -208,6 +208,64 @@ static int wrn_dio_cmd_stamp(struct wrn_drvdata *drvdata,
return 0;
}
static int wrn_dio_cmd_inout(struct wrn_drvdata *drvdata,
struct wr_dio_cmd *cmd)
{
struct DIO_WB __iomem *dio = drvdata->wrdio_base;
int mask, ch, last, bits;
uint32_t reg;
if (cmd->flags & WR_DIO_F_MASK) {
ch = 0;
last = 4;
mask = cmd->channel;
} else {
ch = cmd->channel;
last = ch;
mask = (1 << ch);
cmd->value <<= ch;
}
/* handle the 1-channel and mask case in the same loop */
for (; ch <= last; ch++) {
if (((1 << ch) & mask) == 0)
continue;
/* select the bits by shifting back the value field */
bits = cmd->value >> ch;
/* termination is bit 2 (0x4); register 0 clears, reg 4 sets */
if (bits & WR_DIO_INOUT_TERM)
writel(0x4 << (4 * ch), drvdata->gpio_base + 4);
else
writel(0x4 << (4 * ch), drvdata->gpio_base + 0);
reg = readl(&dio->OUT) & ~(1 << ch);
if (bits & WR_DIO_INOUT_DIO) {
writel(reg | (1 << ch), &dio->OUT);
continue; /* if DIO, nothing more to do */
}
/* If not DIO, wait after we know if input or output */
if (!(bits & WR_DIO_INOUT_OUTPUT)) {
/* output-enable is low-active, so set bit 1 (0x2) */
writel(0x2 << (4 * ch), drvdata->gpio_base + 4);
writel(reg, &dio->OUT); /* not DIO */
continue; /* input, no value to be set */
}
/* Output value is bit 0 (0x1) */
if (bits & WR_DIO_INOUT_VALUE)
writel(0x1 << (4 * ch), drvdata->gpio_base + 4);
else
writel(0x1 << (4 * ch), drvdata->gpio_base + 0);
/* Then clear the low-active output enable, bit 1 (0x2) */
writel(0x2 << (4 * ch), drvdata->gpio_base + 0);
writel(reg, &dio->OUT); /* not DIO */
}
return 0;
}
int wrn_mezzanine_ioctl(struct net_device *dev, struct ifreq *rq,
int ioctlcmd)
......@@ -241,8 +299,10 @@ int wrn_mezzanine_ioctl(struct net_device *dev, struct ifreq *rq,
case WR_DIO_CMD_STAMP:
ret = wrn_dio_cmd_stamp(drvdata, cmd);
break;
case WR_DIO_CMD_DAC:
case WR_DIO_CMD_INOUT:
ret = wrn_dio_cmd_inout(drvdata, cmd);
break;
case WR_DIO_CMD_DAC:
ret = -ENOTSUPP;
goto out;
default:
......
......@@ -136,7 +136,7 @@ static int scan_stamp(int argc, char **argv, int ismask)
break;
fprintf(stderr, "%s: ioctl(PRIV_MEZZANINE_CMD(%s)): "
"%s\n", prgname, ifname, strerror(errno));
return -1;
return -1;
}
for (i = 0; i < cmd->nstamp; i++)
printf("ch %i, %9li.%09li\n", cmd->channel,
......@@ -145,6 +145,92 @@ static int scan_stamp(int argc, char **argv, int ismask)
return 0;
}
static int one_mode(int c, int index)
{
if (c == '-')
return 0;
cmd->channel |= 1 << index;
switch(c) {
case 'D':
cmd->value |= WR_DIO_INOUT_DIO << index;
cmd->value |= WR_DIO_INOUT_TERM << index;
break;
case 'd':
cmd->value |= WR_DIO_INOUT_DIO << index;
break;
case 'I':
cmd->value |= WR_DIO_INOUT_TERM << index;
case 'i':
break;
case '1':
cmd->value |= WR_DIO_INOUT_VALUE << index;
case '0':
cmd->value |= WR_DIO_INOUT_OUTPUT << index;
break;
default:
fprintf(stderr, "%s: mode: invalid mode '%c'\n",
prgname, c);
return -1;
}
return 0;
}
static int scan_inout(int argc, char **argv)
{
int i, ch;
char c;
cmd->flags = WR_DIO_F_MASK;
cmd->channel = 0;
cmd->value = 0;
if (argc == 2) {
if (strlen(argv[1]) != 5) {
fprintf(stderr, "%s: %s: wrong argument \"%s\"\n",
prgname, argv[0], argv[1]);
exit(1);
}
for (i = 0; i < 5; i++)
if (one_mode(argv[1][i], i) < 0)
return -1;
} else {
if (argc < 3 || argc > 11 || ((argc & 1) == 0)) {
fprintf(stderr, "%s: %s: wrong number of arguments\n",
prgname, argv[0]);
return -1;
}
while (argc >= 3) {
if (sscanf(argv[1], "%i%c", &ch, &c) != 1
|| ch < 0 || ch > 4) {
fprintf(stderr, "%s: mode: invalid channel "
"\"%s\"\n", prgname, argv[1]);
return -1;
}
if (strlen(argv[2]) != 1) {
fprintf(stderr, "%s: mode: invalid mode "
"\"%s\"\n", prgname, argv[2]);
return -1;
}
if (one_mode(argv[2][0], ch) < 0)
return -1;
argv += 2;
argc -= 2;
}
}
ifr.ifr_data = (void *)cmd;
if (ioctl(sock, PRIV_MEZZANINE_CMD, &ifr) < 0) {
fprintf(stderr, "%s: ioctl(PRIV_MEZZANINE_CMD(%s)): %s\n",
prgname, ifname, strerror(errno));
return -1;
}
return 0;
}
int main(int argc, char **argv)
{
......@@ -182,12 +268,14 @@ int main(int argc, char **argv)
* pulse <ch> .<len> now
* pulse <ch> .<len> +<seconds>.<fraction>
*
* TODO: stamp <channel>
* TODO: stampm <mask>
**/
* stamp [<channel>]
* stampm [<mask>]
*
* mode <01234>
* mode <ch> <mode> [...]
*/
if (!strcmp(argv[0], "pulse")) {
cmd->command = WR_DIO_CMD_PULSE;
if (scan_pulse(argc, argv) < 0)
exit(1);
} else if (!strcmp(argv[0], "stamp")) {
......@@ -198,6 +286,10 @@ int main(int argc, char **argv)
cmd->command = WR_DIO_CMD_STAMP;
if (scan_stamp(argc, argv, 1 /* mask */) < 0)
exit(1);
} else if (!strcmp(argv[0], "mode")) {
cmd->command = WR_DIO_CMD_INOUT;
if (scan_inout(argc, argv) < 0)
exit(1);
} else {
fprintf(stderr, "%s: unknown command \"%s\"\n", prgname,
argv[0]);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment