can: Merge rh850.c from 3.18

1.can: Don't sent fw_br command
Older versions of rh850 get stuck when
fw_br command received.

2.can: Fix buffer calculation

3.can: rh850 support for CAN FD
This change enables dual mode for CAN raw frames and also CAN FD for property transfer with up to
64 bytes payload for both transmit and receive.

4.can: rh850 CAN FD backward compatibility
This change enables backward compatibility for previous versions of VNW framework to use legacy raw frame mode.

5.can: rh850 support for AMB mode
This enables the AMB driver mode to support
CAN FD frames sent while driver mode is AMB

Change-Id: I0b6939f29ebabeebe2fd32a26fcc67c4386a6cb4
Signed-off-by: Bruce Wu <brucewu@codeaurora.org>
This commit is contained in:
Bruce Wu 2017-03-31 10:49:40 +08:00
parent 0cd8ae5ea9
commit dd9b7cf9a4

View file

@ -1,4 +1,4 @@
/* Copyright (c) 2015-2016, The Linux Foundation. All rights reserved.
/* Copyright (c) 2015-2017, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@ -36,6 +36,9 @@
#define RX_ASSEMBLY_BUFFER_SIZE 128
#define RH850_CLOCK 16000000
#define RH850_MAX_CHANNELS 4
#define DRIVER_MODE_RAW_FRAMES 0
#define DRIVER_MODE_PROPERTIES 1
#define DRIVER_MODE_AMB 2
struct rh850_can {
struct net_device *netdev[RH850_MAX_CHANNELS];
@ -54,6 +57,7 @@ struct rh850_can {
struct completion response_completion;
int wait_cmd;
int cmd_result;
int driver_mode;
};
struct rh850_netdev_privdata {
@ -94,6 +98,8 @@ struct spi_miso { /* TLV for MISO line */
#define CMD_CAN_DATA_BUFF_REMOVE 0X88
#define CMD_CAN_RELEASE_BUFFER 0x89
#define CMD_CAN_DATA_BUFF_REMOVE_ALL 0x8A
#define CMD_PROPERTY_WRITE 0x8B
#define CMD_PROPERTY_READ 0x8C
#define CMD_GET_FW_BR_VERSION 0x95
#define CMD_BEGIN_FIRMWARE_UPGRADE 0x96
@ -166,6 +172,22 @@ struct can_config_bit_timing {
u32 sjw;
} __packed;
struct vehicle_property {
int id;
u64 ts;
int zone;
int val_type;
u32 data_len;
union {
u8 bval;
int val;
int val_arr[4];
float f_value;
float float_arr[4];
u8 str[36];
};
} __packed;
/* IOCTL messages */
struct rh850_release_can_buffer {
u8 enable;
@ -209,6 +231,18 @@ static struct can_bittiming_const rh850_bittiming_const = {
.brp_inc = 1,
};
static struct can_bittiming_const rh850_data_bittiming_const = {
.name = "rh850",
.tseg1_min = 1,
.tseg1_max = 16,
.tseg2_min = 1,
.tseg2_max = 16,
.sjw_max = 4,
.brp_min = 1,
.brp_max = 70,
.brp_inc = 1,
};
static int rh850_rx_message(struct rh850_can *priv_data);
static irqreturn_t rh850_irq(int irq, void *priv)
@ -236,7 +270,7 @@ static void rh850_receive_frame(struct rh850_can *priv_data,
}
netdev = priv_data->netdev[frame->can_if];
skb = alloc_can_skb(netdev, &cf);
if (skb == NULL) {
if (!skb) {
LOGDE("skb alloc failed. frame->can_if %d\n", frame->can_if);
return;
}
@ -262,6 +296,47 @@ static void rh850_receive_frame(struct rh850_can *priv_data,
netdev->stats.rx_packets++;
}
static void rh850_receive_property(struct rh850_can *priv_data,
struct vehicle_property *property)
{
struct canfd_frame *cfd;
u8 *p;
struct sk_buff *skb;
struct skb_shared_hwtstamps *skt;
struct timeval tv;
static u64 nanosec;
struct net_device *netdev;
int i;
/* can0 as the channel with properties */
netdev = priv_data->netdev[0];
skb = alloc_canfd_skb(netdev, &cfd);
if (!skb) {
LOGDE("skb alloc failed. frame->can_if %d\n", 0);
return;
}
LOGDI("rcv property:0x%x data:%2x %2x %2x %2x",
property->id, property->str[0], property->str[1],
property->str[2], property->str[3]);
cfd->can_id = 0x00;
cfd->len = sizeof(struct vehicle_property);
p = (u8 *)property;
for (i = 0; i < cfd->len; i++)
cfd->data[i] = p[i];
nanosec = le64_to_cpu(property->ts);
tv.tv_sec = (int)(nanosec / 1000000000);
tv.tv_usec = (int)(nanosec - (u64)tv.tv_sec * 1000000000) / 1000;
skt = skb_hwtstamps(skb);
skt->hwtstamp = timeval_to_ktime(tv);
LOGDI(" hwtstamp %lld\n", ktime_to_ms(skt->hwtstamp));
skb->tstamp = timeval_to_ktime(tv);
netif_rx(skb);
netdev->stats.rx_packets++;
}
static int rh850_process_response(struct rh850_can *priv_data,
struct spi_miso *resp, int length)
{
@ -280,6 +355,19 @@ static int rh850_process_response(struct rh850_can *priv_data,
} else {
rh850_receive_frame(priv_data, frame);
}
} else if (resp->cmd == CMD_PROPERTY_READ) {
struct vehicle_property *property =
(struct vehicle_property *)&resp->data;
if (resp->len > length) {
LOGDE("Error. This should never happen\n");
LOGDE("process_response: Saving %d bytes\n",
length);
memcpy(priv_data->assembly_buffer, (char *)resp,
length);
priv_data->assembly_buffer_size = length;
} else {
rh850_receive_property(priv_data, property);
}
} else if (resp->cmd == CMD_GET_FW_VERSION) {
struct can_fw_resp *fw_resp = (struct can_fw_resp *)resp->data;
dev_info(&priv_data->spidev->dev, "fw %d.%d",
@ -332,7 +420,8 @@ static int rh850_process_rx(struct rh850_can *priv_data, char *rx_buf)
rx_buf, 2);
data = priv_data->assembly_buffer;
resp = (struct spi_miso *)data;
length = resp->len - priv_data->assembly_buffer_size;
length = resp->len + sizeof(*resp)
- priv_data->assembly_buffer_size;
if (length > 0)
memcpy(priv_data->assembly_buffer +
priv_data->assembly_buffer_size,
@ -353,7 +442,7 @@ static int rh850_process_rx(struct rh850_can *priv_data, char *rx_buf)
length_processed, length_left, priv_data->xfer_length);
length_processed += length;
if (length_left >= sizeof(*resp) &&
resp->len <= length_left) {
resp->len + sizeof(*resp) <= length_left) {
struct spi_miso *resp =
(struct spi_miso *)data;
ret = rh850_process_response(priv_data, resp,
@ -444,30 +533,6 @@ static int rh850_query_firmware_version(struct rh850_can *priv_data)
return ret;
}
static int rh850_query_firmware_br_version(struct rh850_can *priv_data)
{
char *tx_buf, *rx_buf;
int ret;
struct spi_mosi *req;
mutex_lock(&priv_data->spi_lock);
tx_buf = priv_data->tx_buf;
rx_buf = priv_data->rx_buf;
memset(tx_buf, 0, XFER_BUFFER_SIZE);
memset(rx_buf, 0, XFER_BUFFER_SIZE);
priv_data->xfer_length = XFER_BUFFER_SIZE;
req = (struct spi_mosi *)tx_buf;
req->cmd = CMD_GET_FW_BR_VERSION;
req->len = 0;
req->seq = atomic_inc_return(&priv_data->msg_seq);
ret = rh850_do_spi_transaction(priv_data);
mutex_unlock(&priv_data->spi_lock);
return ret;
}
static int rh850_set_bitrate(struct net_device *netdev)
{
char *tx_buf, *rx_buf;
@ -515,7 +580,7 @@ static int rh850_set_bitrate(struct net_device *netdev)
}
static int rh850_can_write(struct rh850_can *priv_data,
int can_channel, struct can_frame *cf)
int can_channel, struct canfd_frame *cf)
{
char *tx_buf, *rx_buf;
int ret, i;
@ -536,16 +601,29 @@ static int rh850_can_write(struct rh850_can *priv_data,
priv_data->xfer_length = XFER_BUFFER_SIZE;
req = (struct spi_mosi *)tx_buf;
req->cmd = CMD_CAN_SEND_FRAME;
req->len = sizeof(struct can_write_req) + 8;
req->seq = atomic_inc_return(&priv_data->msg_seq);
if (priv_data->driver_mode == DRIVER_MODE_RAW_FRAMES) {
req->cmd = CMD_CAN_SEND_FRAME;
req->len = sizeof(struct can_write_req) + 8;
req->seq = atomic_inc_return(&priv_data->msg_seq);
req_d = (struct can_write_req *)req->data;
req_d->can_if = can_channel;
req_d->mid = cf->can_id;
req_d->dlc = cf->can_dlc;
for (i = 0; i < cf->can_dlc; i++)
req_d->data[i] = cf->data[i];
req_d = (struct can_write_req *)req->data;
req_d->can_if = can_channel;
req_d->mid = cf->can_id;
req_d->dlc = cf->len;
for (i = 0; i < cf->len; i++)
req_d->data[i] = cf->data[i];
} else if (priv_data->driver_mode == DRIVER_MODE_PROPERTIES ||
priv_data->driver_mode == DRIVER_MODE_AMB) {
req->cmd = CMD_PROPERTY_WRITE;
req->len = sizeof(struct vehicle_property);
req->seq = atomic_inc_return(&priv_data->msg_seq);
for (i = 0; i < cf->len; i++)
req->data[i] = cf->data[i];
} else {
LOGDE("rh850_can_write: wrong driver mode %i",
priv_data->driver_mode);
}
ret = rh850_do_spi_transaction(priv_data);
netdev = priv_data->netdev[can_channel];
@ -581,7 +659,7 @@ static int rh850_netdev_close(struct net_device *netdev)
static void rh850_send_can_frame(struct work_struct *ws)
{
struct rh850_tx_work *tx_work;
struct can_frame *cf;
struct canfd_frame *cf;
struct rh850_can *priv_data;
struct net_device *netdev;
struct rh850_netdev_privdata *netdev_priv_data;
@ -595,7 +673,7 @@ static void rh850_send_can_frame(struct work_struct *ws)
LOGDI("send_can_frame ws %p\n", ws);
LOGDI("send_can_frame tx %p\n", tx_work);
cf = (struct can_frame *)tx_work->skb->data;
cf = (struct canfd_frame *)tx_work->skb->data;
rh850_can_write(priv_data, can_channel, cf);
dev_kfree_skb(tx_work->skb);
@ -632,6 +710,7 @@ static int rh850_send_release_can_buffer_cmd(struct net_device *netdev)
struct spi_mosi *req;
struct rh850_can *priv_data;
struct rh850_netdev_privdata *netdev_priv_data;
int *mode;
netdev_priv_data = netdev_priv(netdev);
priv_data = netdev_priv_data->rh850_can;
@ -644,8 +723,10 @@ static int rh850_send_release_can_buffer_cmd(struct net_device *netdev)
req = (struct spi_mosi *)tx_buf;
req->cmd = CMD_CAN_RELEASE_BUFFER;
req->len = 0;
req->len = sizeof(int);
req->seq = atomic_inc_return(&priv_data->msg_seq);
mode = (int *)req->data;
*mode = priv_data->driver_mode;
ret = rh850_do_spi_transaction(priv_data);
mutex_unlock(&priv_data->spi_lock);
@ -845,8 +926,7 @@ static int rh850_do_blocking_ioctl(struct net_device *netdev,
len = ioctl_data->len;
data = ioctl_data->data;
}
LOGDI("rh850_do_blocking_ioctl len and data %d %x\n",
len, (void *)data);
LOGDI("rh850_do_blocking_ioctl len %d\n", len);
mutex_lock(&priv_data->spi_lock);
priv_data->wait_cmd = spi_cmd;
@ -870,6 +950,7 @@ static int rh850_netdev_do_ioctl(struct net_device *netdev,
{
struct rh850_can *priv_data;
struct rh850_netdev_privdata *netdev_priv_data;
int *mode;
int ret = -EINVAL;
netdev_priv_data = netdev_priv(netdev);
@ -878,6 +959,11 @@ static int rh850_netdev_do_ioctl(struct net_device *netdev,
switch (cmd) {
case IOCTL_RELEASE_CAN_BUFFER:
if (ifr->ifr_data > (void *)0x100) {
mode = ifr->ifr_data;
priv_data->driver_mode = *mode;
}
LOGDE("rh850_driver_mode %d\n", priv_data->driver_mode);
rh850_send_release_can_buffer_cmd(netdev);
ret = 0;
break;
@ -943,8 +1029,11 @@ static int rh850_create_netdev(struct spi_device *spi,
netdev->netdev_ops = &rh850_netdev_ops;
SET_NETDEV_DEV(netdev, &spi->dev);
netdev_priv_data->can.ctrlmode_supported = CAN_CTRLMODE_3_SAMPLES |
CAN_CTRLMODE_LISTENONLY;
CAN_CTRLMODE_LISTENONLY |
CAN_CTRLMODE_FD;
netdev_priv_data->can.bittiming_const = &rh850_bittiming_const;
netdev_priv_data->can.data_bittiming_const =
&rh850_data_bittiming_const;
netdev_priv_data->can.clock.freq = RH850_CLOCK;
netdev_priv_data->can.do_set_bittiming = rh850_set_bitrate;
@ -988,6 +1077,7 @@ static struct rh850_can *rh850_create_priv_data(struct spi_device *spi)
goto cleanup_privdata;
}
priv_data->xfer_length = 0;
priv_data->driver_mode = DRIVER_MODE_RAW_FRAMES;
mutex_init(&priv_data->spi_lock);
atomic_set(&priv_data->msg_seq, 0);
@ -1052,7 +1142,6 @@ static int rh850_probe(struct spi_device *spi)
dev_info(dev, "Request irq %d ret %d\n", spi->irq, err);
rh850_query_firmware_version(priv_data);
rh850_query_firmware_br_version(priv_data);
return 0;
unregister_candev: