diff options
Diffstat (limited to 'drivers/staging/fsl-dpaa2')
-rw-r--r-- | drivers/staging/fsl-dpaa2/Kconfig | 8 | ||||
-rw-r--r-- | drivers/staging/fsl-dpaa2/Makefile | 5 | ||||
-rw-r--r-- | drivers/staging/fsl-dpaa2/ethernet/dpaa2-eth.c | 111 | ||||
-rw-r--r-- | drivers/staging/fsl-dpaa2/ethernet/dpaa2-eth.h | 49 | ||||
-rw-r--r-- | drivers/staging/fsl-dpaa2/ethernet/dpaa2-ethtool.c | 23 | ||||
-rw-r--r-- | drivers/staging/fsl-dpaa2/ethsw/dpsw-cmd.h | 13 | ||||
-rw-r--r-- | drivers/staging/fsl-dpaa2/ethsw/dpsw.c | 42 | ||||
-rw-r--r-- | drivers/staging/fsl-dpaa2/ethsw/dpsw.h | 6 | ||||
-rw-r--r-- | drivers/staging/fsl-dpaa2/ethsw/ethsw.c | 39 | ||||
-rw-r--r-- | drivers/staging/fsl-dpaa2/rtc/Makefile | 7 | ||||
-rw-r--r-- | drivers/staging/fsl-dpaa2/rtc/dprtc-cmd.h | 137 | ||||
-rw-r--r-- | drivers/staging/fsl-dpaa2/rtc/dprtc.c | 701 | ||||
-rw-r--r-- | drivers/staging/fsl-dpaa2/rtc/dprtc.h | 164 | ||||
-rw-r--r-- | drivers/staging/fsl-dpaa2/rtc/rtc.c | 229 | ||||
-rw-r--r-- | drivers/staging/fsl-dpaa2/rtc/rtc.h | 14 |
15 files changed, 1519 insertions, 29 deletions
diff --git a/drivers/staging/fsl-dpaa2/Kconfig b/drivers/staging/fsl-dpaa2/Kconfig index bbb7af551696..a4c4b83ddc9c 100644 --- a/drivers/staging/fsl-dpaa2/Kconfig +++ b/drivers/staging/fsl-dpaa2/Kconfig @@ -24,3 +24,11 @@ config FSL_DPAA2_ETHSW ---help--- Driver for Freescale DPAA2 Ethernet Switch. Select BRIDGE to have support for bridge tools. + +config FSL_DPAA2_PTP_CLOCK + tristate "Freescale DPAA2 PTP Clock" + depends on FSL_DPAA2_ETH && POSIX_TIMERS + select PTP_1588_CLOCK + help + This driver adds support for using the DPAA2 1588 timer module + as a PTP clock. diff --git a/drivers/staging/fsl-dpaa2/Makefile b/drivers/staging/fsl-dpaa2/Makefile index 6cfd76b29970..9c7062945758 100644 --- a/drivers/staging/fsl-dpaa2/Makefile +++ b/drivers/staging/fsl-dpaa2/Makefile @@ -2,5 +2,6 @@ # Freescale DataPath Acceleration Architecture Gen2 (DPAA2) drivers # -obj-$(CONFIG_FSL_DPAA2_ETH) += ethernet/ -obj-$(CONFIG_FSL_DPAA2_ETHSW) += ethsw/ +obj-$(CONFIG_FSL_DPAA2_ETH) += ethernet/ +obj-$(CONFIG_FSL_DPAA2_ETHSW) += ethsw/ +obj-$(CONFIG_FSL_DPAA2_PTP_CLOCK) += rtc/ diff --git a/drivers/staging/fsl-dpaa2/ethernet/dpaa2-eth.c b/drivers/staging/fsl-dpaa2/ethernet/dpaa2-eth.c index 553678d8b2eb..396371728aa1 100644 --- a/drivers/staging/fsl-dpaa2/ethernet/dpaa2-eth.c +++ b/drivers/staging/fsl-dpaa2/ethernet/dpaa2-eth.c @@ -38,8 +38,11 @@ #include <linux/msi.h> #include <linux/kthread.h> #include <linux/iommu.h> - +#include <linux/net_tstamp.h> #include <linux/fsl/mc.h> + +#include <net/sock.h> + #include "dpaa2-eth.h" /* CREATE_TRACE_POINTS only needs to be defined once. Other dpa files @@ -275,6 +278,18 @@ static void dpaa2_eth_rx(struct dpaa2_eth_priv *priv, prefetch(skb->data); + /* Get the timestamp value */ + if (priv->rx_tstamp) { + struct skb_shared_hwtstamps *shhwtstamps = skb_hwtstamps(skb); + __le64 *ts = dpaa2_get_ts(vaddr, false); + u64 ns; + + memset(shhwtstamps, 0, sizeof(*shhwtstamps)); + + ns = DPAA2_PTP_CLK_PERIOD_NS * le64_to_cpup(ts); + shhwtstamps->hwtstamp = ns_to_ktime(ns); + } + /* Check if we need to validate the L4 csum */ if (likely(dpaa2_fd_get_frc(fd) & DPAA2_FD_FRC_FASV)) { status = le32_to_cpu(fas->status); @@ -334,6 +349,28 @@ static int consume_frames(struct dpaa2_eth_channel *ch) return cleaned; } +/* Configure the egress frame annotation for timestamp update */ +static void enable_tx_tstamp(struct dpaa2_fd *fd, void *buf_start) +{ + struct dpaa2_faead *faead; + u32 ctrl, frc; + + /* Mark the egress frame annotation area as valid */ + frc = dpaa2_fd_get_frc(fd); + dpaa2_fd_set_frc(fd, frc | DPAA2_FD_FRC_FAEADV); + + /* Set hardware annotation size */ + ctrl = dpaa2_fd_get_ctrl(fd); + dpaa2_fd_set_ctrl(fd, ctrl | DPAA2_FD_CTRL_ASAL); + + /* enable UPD (update prepanded data) bit in FAEAD field of + * hardware frame annotation area + */ + ctrl = DPAA2_FAEAD_A2V | DPAA2_FAEAD_UPDV | DPAA2_FAEAD_UPD; + faead = dpaa2_get_faead(buf_start, true); + faead->ctrl = cpu_to_le32(ctrl); +} + /* Create a frame descriptor based on a fragmented skb */ static int build_sg_fd(struct dpaa2_eth_priv *priv, struct sk_buff *skb, @@ -420,6 +457,9 @@ static int build_sg_fd(struct dpaa2_eth_priv *priv, dpaa2_fd_set_len(fd, skb->len); dpaa2_fd_set_ctrl(fd, DPAA2_FD_CTRL_PTA | DPAA2_FD_CTRL_PTV1); + if (priv->tx_tstamp && skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP) + enable_tx_tstamp(fd, sgt_buf); + return 0; dma_map_single_failed: @@ -470,6 +510,9 @@ static int build_single_fd(struct dpaa2_eth_priv *priv, dpaa2_fd_set_format(fd, dpaa2_fd_single); dpaa2_fd_set_ctrl(fd, DPAA2_FD_CTRL_PTA | DPAA2_FD_CTRL_PTV1); + if (priv->tx_tstamp && skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP) + enable_tx_tstamp(fd, buffer_start); + return 0; } @@ -520,6 +563,19 @@ static void free_tx_fd(const struct dpaa2_eth_priv *priv, return; } + /* Get the timestamp value */ + if (priv->tx_tstamp && skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP) { + struct skb_shared_hwtstamps shhwtstamps; + __le64 *ts = dpaa2_get_ts(skbh, true); + u64 ns; + + memset(&shhwtstamps, 0, sizeof(shhwtstamps)); + + ns = DPAA2_PTP_CLK_PERIOD_NS * le64_to_cpup(ts); + shhwtstamps.hwtstamp = ns_to_ktime(ns); + skb_tstamp_tx(skb, &shhwtstamps); + } + /* Free SGT buffer allocated on tx */ if (fd_format != dpaa2_fd_single) skb_free_frag(skbh); @@ -552,6 +608,10 @@ static netdev_tx_t dpaa2_eth_tx(struct sk_buff *skb, struct net_device *net_dev) goto err_alloc_headroom; } percpu_extras->tx_reallocs++; + + if (skb->sk) + skb_set_owner_w(ns, skb->sk); + dev_kfree_skb(skb); skb = ns; } @@ -1365,6 +1425,45 @@ static int dpaa2_eth_set_features(struct net_device *net_dev, return 0; } +static int dpaa2_eth_ts_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) +{ + struct dpaa2_eth_priv *priv = netdev_priv(dev); + struct hwtstamp_config config; + + if (copy_from_user(&config, rq->ifr_data, sizeof(config))) + return -EFAULT; + + switch (config.tx_type) { + case HWTSTAMP_TX_OFF: + priv->tx_tstamp = false; + break; + case HWTSTAMP_TX_ON: + priv->tx_tstamp = true; + break; + default: + return -ERANGE; + } + + if (config.rx_filter == HWTSTAMP_FILTER_NONE) { + priv->rx_tstamp = false; + } else { + priv->rx_tstamp = true; + /* TS is set for all frame types, not only those requested */ + config.rx_filter = HWTSTAMP_FILTER_ALL; + } + + return copy_to_user(rq->ifr_data, &config, sizeof(config)) ? + -EFAULT : 0; +} + +static int dpaa2_eth_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) +{ + if (cmd == SIOCSHWTSTAMP) + return dpaa2_eth_ts_ioctl(dev, rq, cmd); + + return -EINVAL; +} + static const struct net_device_ops dpaa2_eth_ops = { .ndo_open = dpaa2_eth_open, .ndo_start_xmit = dpaa2_eth_tx, @@ -1375,6 +1474,7 @@ static const struct net_device_ops dpaa2_eth_ops = { .ndo_change_mtu = dpaa2_eth_change_mtu, .ndo_set_rx_mode = dpaa2_eth_set_rx_mode, .ndo_set_features = dpaa2_eth_set_features, + .ndo_do_ioctl = dpaa2_eth_ioctl, }; static void cdan_cb(struct dpaa2_io_notification_ctx *ctx) @@ -1770,7 +1870,9 @@ static int set_buffer_layout(struct dpaa2_eth_priv *priv) /* tx buffer */ buf_layout.private_data_size = DPAA2_ETH_SWA_SIZE; - buf_layout.options = DPNI_BUF_LAYOUT_OPT_PRIVATE_DATA_SIZE; + buf_layout.pass_timestamp = true; + buf_layout.options = DPNI_BUF_LAYOUT_OPT_PRIVATE_DATA_SIZE | + DPNI_BUF_LAYOUT_OPT_TIMESTAMP; err = dpni_set_buffer_layout(priv->mc_io, 0, priv->mc_token, DPNI_QUEUE_TX, &buf_layout); if (err) { @@ -1779,7 +1881,7 @@ static int set_buffer_layout(struct dpaa2_eth_priv *priv) } /* tx-confirm buffer */ - buf_layout.options = 0; + buf_layout.options = DPNI_BUF_LAYOUT_OPT_TIMESTAMP; err = dpni_set_buffer_layout(priv->mc_io, 0, priv->mc_token, DPNI_QUEUE_TX_CONFIRM, &buf_layout); if (err) { @@ -1810,7 +1912,8 @@ static int set_buffer_layout(struct dpaa2_eth_priv *priv) buf_layout.options = DPNI_BUF_LAYOUT_OPT_PARSER_RESULT | DPNI_BUF_LAYOUT_OPT_FRAME_STATUS | DPNI_BUF_LAYOUT_OPT_DATA_ALIGN | - DPNI_BUF_LAYOUT_OPT_DATA_HEAD_ROOM; + DPNI_BUF_LAYOUT_OPT_DATA_HEAD_ROOM | + DPNI_BUF_LAYOUT_OPT_TIMESTAMP; err = dpni_set_buffer_layout(priv->mc_io, 0, priv->mc_token, DPNI_QUEUE_RX, &buf_layout); if (err) { diff --git a/drivers/staging/fsl-dpaa2/ethernet/dpaa2-eth.h b/drivers/staging/fsl-dpaa2/ethernet/dpaa2-eth.h index 54cea2fc6e58..905a4e6be8fa 100644 --- a/drivers/staging/fsl-dpaa2/ethernet/dpaa2-eth.h +++ b/drivers/staging/fsl-dpaa2/ethernet/dpaa2-eth.h @@ -88,8 +88,12 @@ #define DPAA2_ETH_SKB_SIZE \ (DPAA2_ETH_RX_BUF_SIZE + SKB_DATA_ALIGN(sizeof(struct skb_shared_info))) -/* Hardware annotation area in RX buffers */ +/* Hardware annotation area in RX/TX buffers */ #define DPAA2_ETH_RX_HWA_SIZE 64 +#define DPAA2_ETH_TX_HWA_SIZE 128 + +/* PTP nominal frequency 1GHz */ +#define DPAA2_PTP_CLK_PERIOD_NS 1 /* Due to a limitation in WRIOP 1.0.0, the RX buffer data must be aligned * to 256B. For newer revisions, the requirement is only for 64B alignment @@ -135,6 +139,7 @@ struct dpaa2_eth_swa { /* Annotation bits in FD CTRL */ #define DPAA2_FD_CTRL_PTA 0x00800000 #define DPAA2_FD_CTRL_PTV1 0x00400000 +#define DPAA2_FD_CTRL_ASAL 0x00020000 /* ASAL = 128B */ /* Frame annotation status */ struct dpaa2_fas { @@ -150,6 +155,23 @@ struct dpaa2_fas { #define DPAA2_FAS_OFFSET 0 #define DPAA2_FAS_SIZE (sizeof(struct dpaa2_fas)) +/* Timestamp is located in the next 8 bytes of the buffer's + * hardware annotation area + */ +#define DPAA2_TS_OFFSET 0x8 + +/* Frame annotation egress action descriptor */ +#define DPAA2_FAEAD_OFFSET 0x58 + +struct dpaa2_faead { + __le32 conf_fqid; + __le32 ctrl; +}; + +#define DPAA2_FAEAD_A2V 0x20000000 +#define DPAA2_FAEAD_UPDV 0x00001000 +#define DPAA2_FAEAD_UPD 0x00000010 + /* Accessors for the hardware annotation fields that we use */ static inline void *dpaa2_get_hwa(void *buf_addr, bool swa) { @@ -161,6 +183,16 @@ static inline struct dpaa2_fas *dpaa2_get_fas(void *buf_addr, bool swa) return dpaa2_get_hwa(buf_addr, swa) + DPAA2_FAS_OFFSET; } +static inline __le64 *dpaa2_get_ts(void *buf_addr, bool swa) +{ + return dpaa2_get_hwa(buf_addr, swa) + DPAA2_TS_OFFSET; +} + +static inline struct dpaa2_faead *dpaa2_get_faead(void *buf_addr, bool swa) +{ + return dpaa2_get_hwa(buf_addr, swa) + DPAA2_FAEAD_OFFSET; +} + /* Error and status bits in the frame annotation status word */ /* Debug frame, otherwise supposed to be discarded */ #define DPAA2_FAS_DISC 0x80000000 @@ -319,6 +351,9 @@ struct dpaa2_eth_priv { u16 bpid; struct iommu_domain *iommu_domain; + bool tx_tstamp; /* Tx timestamping enabled */ + bool rx_tstamp; /* Rx timestamping enabled */ + u16 tx_qdid; u16 rx_buf_align; struct fsl_mc_io *mc_io; @@ -355,6 +390,7 @@ struct dpaa2_eth_priv { extern const struct ethtool_ops dpaa2_ethtool_ops; extern const char dpaa2_eth_drv_version[]; +extern int dpaa2_phc_index; static inline int dpaa2_eth_cmp_dpni_ver(struct dpaa2_eth_priv *priv, u16 ver_major, u16 ver_minor) @@ -377,10 +413,19 @@ static inline unsigned int dpaa2_eth_needed_headroom(struct dpaa2_eth_priv *priv, struct sk_buff *skb) { + unsigned int headroom = DPAA2_ETH_SWA_SIZE; + + /* For non-linear skbs we have no headroom requirement, as we build a + * SG frame with a newly allocated SGT buffer + */ if (skb_is_nonlinear(skb)) return 0; - return DPAA2_ETH_SWA_SIZE; + /* If we have Tx timestamping, need 128B hardware annotation */ + if (priv->tx_tstamp && skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP) + headroom += DPAA2_ETH_TX_HWA_SIZE; + + return headroom; } /* Extra headroom space requested to hardware, in order to make sure there's diff --git a/drivers/staging/fsl-dpaa2/ethernet/dpaa2-ethtool.c b/drivers/staging/fsl-dpaa2/ethernet/dpaa2-ethtool.c index bfc8b64169ca..1ae779ae8c99 100644 --- a/drivers/staging/fsl-dpaa2/ethernet/dpaa2-ethtool.c +++ b/drivers/staging/fsl-dpaa2/ethernet/dpaa2-ethtool.c @@ -30,6 +30,8 @@ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +#include <linux/net_tstamp.h> + #include "dpni.h" /* DPNI_LINK_OPT_* */ #include "dpaa2-eth.h" @@ -274,6 +276,26 @@ static int dpaa2_eth_get_rxnfc(struct net_device *net_dev, return 0; } +int dpaa2_phc_index = -1; +EXPORT_SYMBOL(dpaa2_phc_index); + +static int dpaa2_eth_get_ts_info(struct net_device *dev, + struct ethtool_ts_info *info) +{ + info->so_timestamping = SOF_TIMESTAMPING_TX_HARDWARE | + SOF_TIMESTAMPING_RX_HARDWARE | + SOF_TIMESTAMPING_RAW_HARDWARE; + + info->phc_index = dpaa2_phc_index; + + info->tx_types = (1 << HWTSTAMP_TX_OFF) | + (1 << HWTSTAMP_TX_ON); + + info->rx_filters = (1 << HWTSTAMP_FILTER_NONE) | + (1 << HWTSTAMP_FILTER_ALL); + return 0; +} + const struct ethtool_ops dpaa2_ethtool_ops = { .get_drvinfo = dpaa2_eth_get_drvinfo, .get_link = ethtool_op_get_link, @@ -283,4 +305,5 @@ const struct ethtool_ops dpaa2_ethtool_ops = { .get_ethtool_stats = dpaa2_eth_get_ethtool_stats, .get_strings = dpaa2_eth_get_strings, .get_rxnfc = dpaa2_eth_get_rxnfc, + .get_ts_info = dpaa2_eth_get_ts_info, }; diff --git a/drivers/staging/fsl-dpaa2/ethsw/dpsw-cmd.h b/drivers/staging/fsl-dpaa2/ethsw/dpsw-cmd.h index 1c203e6e8035..da744f2b0ee6 100644 --- a/drivers/staging/fsl-dpaa2/ethsw/dpsw-cmd.h +++ b/drivers/staging/fsl-dpaa2/ethsw/dpsw-cmd.h @@ -49,6 +49,8 @@ #define DPSW_CMDID_IF_SET_FLOODING DPSW_CMD_ID(0x047) #define DPSW_CMDID_IF_SET_BROADCAST DPSW_CMD_ID(0x048) +#define DPSW_CMDID_IF_GET_TCI DPSW_CMD_ID(0x04A) + #define DPSW_CMDID_IF_SET_LINK_CFG DPSW_CMD_ID(0x04C) #define DPSW_CMDID_VLAN_ADD DPSW_CMD_ID(0x060) @@ -206,6 +208,17 @@ struct dpsw_cmd_if_set_tci { __le16 conf; }; +struct dpsw_cmd_if_get_tci { + __le16 if_id; +}; + +struct dpsw_rsp_if_get_tci { + __le16 pad; + __le16 vlan_id; + u8 dei; + u8 pcp; +}; + #define DPSW_STATE_SHIFT 0 #define DPSW_STATE_SIZE 4 diff --git a/drivers/staging/fsl-dpaa2/ethsw/dpsw.c b/drivers/staging/fsl-dpaa2/ethsw/dpsw.c index 9b9bc604b461..cabed77b445d 100644 --- a/drivers/staging/fsl-dpaa2/ethsw/dpsw.c +++ b/drivers/staging/fsl-dpaa2/ethsw/dpsw.c @@ -529,6 +529,48 @@ int dpsw_if_set_tci(struct fsl_mc_io *mc_io, } /** + * dpsw_if_get_tci() - Get default VLAN Tag Control Information (TCI) + * @mc_io: Pointer to MC portal's I/O object + * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' + * @token: Token of DPSW object + * @if_id: Interface Identifier + * @cfg: Tag Control Information Configuration + * + * Return: Completion status. '0' on Success; Error code otherwise. + */ +int dpsw_if_get_tci(struct fsl_mc_io *mc_io, + u32 cmd_flags, + u16 token, + u16 if_id, + struct dpsw_tci_cfg *cfg) +{ + struct fsl_mc_command cmd = { 0 }; + struct dpsw_cmd_if_get_tci *cmd_params; + struct dpsw_rsp_if_get_tci *rsp_params; + int err; + + /* prepare command */ + cmd.header = mc_encode_cmd_header(DPSW_CMDID_IF_GET_TCI, + cmd_flags, + token); + cmd_params = (struct dpsw_cmd_if_get_tci *)cmd.params; + cmd_params->if_id = cpu_to_le16(if_id); + + /* send command to mc*/ + err = mc_send_command(mc_io, &cmd); + if (err) + return err; + + /* retrieve response parameters */ + rsp_params = (struct dpsw_rsp_if_get_tci *)cmd.params; + cfg->pcp = rsp_params->pcp; + cfg->dei = rsp_params->dei; + cfg->vlan_id = le16_to_cpu(rsp_params->vlan_id); + + return 0; +} + +/** * dpsw_if_set_stp() - Function sets Spanning Tree Protocol (STP) state. * @mc_io: Pointer to MC portal's I/O object * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' diff --git a/drivers/staging/fsl-dpaa2/ethsw/dpsw.h b/drivers/staging/fsl-dpaa2/ethsw/dpsw.h index 3335adde0193..82f80c409ec3 100644 --- a/drivers/staging/fsl-dpaa2/ethsw/dpsw.h +++ b/drivers/staging/fsl-dpaa2/ethsw/dpsw.h @@ -306,6 +306,12 @@ int dpsw_if_set_tci(struct fsl_mc_io *mc_io, u16 if_id, const struct dpsw_tci_cfg *cfg); +int dpsw_if_get_tci(struct fsl_mc_io *mc_io, + u32 cmd_flags, + u16 token, + u16 if_id, + struct dpsw_tci_cfg *cfg); + /** * enum dpsw_stp_state - Spanning Tree Protocol (STP) states * @DPSW_STP_STATE_BLOCKING: Blocking state diff --git a/drivers/staging/fsl-dpaa2/ethsw/ethsw.c b/drivers/staging/fsl-dpaa2/ethsw/ethsw.c index a17dd2972ccd..0d54564e4f38 100644 --- a/drivers/staging/fsl-dpaa2/ethsw/ethsw.c +++ b/drivers/staging/fsl-dpaa2/ethsw/ethsw.c @@ -50,14 +50,23 @@ static int ethsw_add_vlan(struct ethsw_core *ethsw, u16 vid) return 0; } -static int ethsw_port_set_tci(struct ethsw_port_priv *port_priv, - struct dpsw_tci_cfg *tci_cfg) +static int ethsw_port_set_pvid(struct ethsw_port_priv *port_priv, u16 pvid) { struct ethsw_core *ethsw = port_priv->ethsw_data; struct net_device *netdev = port_priv->netdev; + struct dpsw_tci_cfg tci_cfg = { 0 }; bool is_oper; int err, ret; + err = dpsw_if_get_tci(ethsw->mc_io, 0, ethsw->dpsw_handle, + port_priv->idx, &tci_cfg); + if (err) { + netdev_err(netdev, "dpsw_if_get_tci err %d\n", err); + return err; + } + + tci_cfg.vlan_id = pvid; + /* Interface needs to be down to change PVID */ is_oper = netif_oper_up(netdev); if (is_oper) { @@ -71,17 +80,16 @@ static int ethsw_port_set_tci(struct ethsw_port_priv *port_priv, } err = dpsw_if_set_tci(ethsw->mc_io, 0, ethsw->dpsw_handle, - port_priv->idx, tci_cfg); + port_priv->idx, &tci_cfg); if (err) { netdev_err(netdev, "dpsw_if_set_tci err %d\n", err); goto set_tci_error; } /* Delete previous PVID info and mark the new one */ - if (port_priv->pvid) - port_priv->vlans[port_priv->pvid] &= ~ETHSW_VLAN_PVID; - port_priv->vlans[tci_cfg->vlan_id] |= ETHSW_VLAN_PVID; - port_priv->pvid = tci_cfg->vlan_id; + port_priv->vlans[port_priv->pvid] &= ~ETHSW_VLAN_PVID; + port_priv->vlans[pvid] |= ETHSW_VLAN_PVID; + port_priv->pvid = pvid; set_tci_error: if (is_oper) { @@ -133,13 +141,7 @@ static int ethsw_port_add_vlan(struct ethsw_port_priv *port_priv, } if (flags & BRIDGE_VLAN_INFO_PVID) { - struct dpsw_tci_cfg tci_cfg = { - .pcp = 0, - .dei = 0, - .vlan_id = vid, - }; - - err = ethsw_port_set_tci(port_priv, &tci_cfg); + err = ethsw_port_set_pvid(port_priv, vid); if (err) return err; } @@ -616,10 +618,8 @@ static void ethsw_teardown_irqs(struct fsl_mc_device *sw_dev) { struct device *dev = &sw_dev->dev; struct ethsw_core *ethsw = dev_get_drvdata(dev); - struct fsl_mc_device_irq *irq; int err; - irq = sw_dev->irqs[DPSW_IRQ_INDEX_IF]; err = dpsw_set_irq_enable(ethsw->mc_io, 0, ethsw->dpsw_handle, DPSW_IRQ_INDEX_IF, 0); if (err) @@ -822,9 +822,7 @@ static int ethsw_port_del_vlan(struct ethsw_port_priv *port_priv, u16 vid) return -ENOENT; if (port_priv->vlans[vid] & ETHSW_VLAN_PVID) { - struct dpsw_tci_cfg tci_cfg = { 0 }; - - err = ethsw_port_set_tci(port_priv, &tci_cfg); + err = ethsw_port_set_pvid(port_priv, 0); if (err) return err; } @@ -1260,7 +1258,6 @@ static int ethsw_port_init(struct ethsw_port_priv *port_priv, u16 port) const char def_mcast[ETH_ALEN] = {0x01, 0x00, 0x5e, 0x00, 0x00, 0x01}; struct net_device *netdev = port_priv->netdev; struct ethsw_core *ethsw = port_priv->ethsw_data; - struct dpsw_tci_cfg tci_cfg = {0}; struct dpsw_vlan_if_cfg vcfg; int err; @@ -1278,7 +1275,7 @@ static int ethsw_port_init(struct ethsw_port_priv *port_priv, u16 port) return err; } - err = ethsw_port_set_tci(port_priv, &tci_cfg); + err = ethsw_port_set_pvid(port_priv, 0); if (err) return err; diff --git a/drivers/staging/fsl-dpaa2/rtc/Makefile b/drivers/staging/fsl-dpaa2/rtc/Makefile new file mode 100644 index 000000000000..5468da071163 --- /dev/null +++ b/drivers/staging/fsl-dpaa2/rtc/Makefile @@ -0,0 +1,7 @@ +# +# Makefile for the Freescale DPAA2 PTP clock +# + +obj-$(CONFIG_FSL_DPAA2_PTP_CLOCK) += dpaa2-rtc.o + +dpaa2-rtc-objs := rtc.o dprtc.o diff --git a/drivers/staging/fsl-dpaa2/rtc/dprtc-cmd.h b/drivers/staging/fsl-dpaa2/rtc/dprtc-cmd.h new file mode 100644 index 000000000000..db6a473430cc --- /dev/null +++ b/drivers/staging/fsl-dpaa2/rtc/dprtc-cmd.h @@ -0,0 +1,137 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright 2013-2016 Freescale Semiconductor Inc. + * Copyright 2016-2018 NXP + */ + +#ifndef _FSL_DPRTC_CMD_H +#define _FSL_DPRTC_CMD_H + +/* DPRTC Version */ +#define DPRTC_VER_MAJOR 2 +#define DPRTC_VER_MINOR 0 + +/* Command versioning */ +#define DPRTC_CMD_BASE_VERSION 1 +#define DPRTC_CMD_ID_OFFSET 4 + +#define DPRTC_CMD(id) (((id) << DPRTC_CMD_ID_OFFSET) | DPRTC_CMD_BASE_VERSION) + +/* Command IDs */ +#define DPRTC_CMDID_CLOSE DPRTC_CMD(0x800) +#define DPRTC_CMDID_OPEN DPRTC_CMD(0x810) +#define DPRTC_CMDID_CREATE DPRTC_CMD(0x910) +#define DPRTC_CMDID_DESTROY DPRTC_CMD(0x990) +#define DPRTC_CMDID_GET_API_VERSION DPRTC_CMD(0xa10) + +#define DPRTC_CMDID_ENABLE DPRTC_CMD(0x002) +#define DPRTC_CMDID_DISABLE DPRTC_CMD(0x003) +#define DPRTC_CMDID_GET_ATTR DPRTC_CMD(0x004) +#define DPRTC_CMDID_RESET DPRTC_CMD(0x005) +#define DPRTC_CMDID_IS_ENABLED DPRTC_CMD(0x006) + +#define DPRTC_CMDID_SET_IRQ_ENABLE DPRTC_CMD(0x012) +#define DPRTC_CMDID_GET_IRQ_ENABLE DPRTC_CMD(0x013) +#define DPRTC_CMDID_SET_IRQ_MASK DPRTC_CMD(0x014) +#define DPRTC_CMDID_GET_IRQ_MASK DPRTC_CMD(0x015) +#define DPRTC_CMDID_GET_IRQ_STATUS DPRTC_CMD(0x016) +#define DPRTC_CMDID_CLEAR_IRQ_STATUS DPRTC_CMD(0x017) + +#define DPRTC_CMDID_SET_CLOCK_OFFSET DPRTC_CMD(0x1d0) +#define DPRTC_CMDID_SET_FREQ_COMPENSATION DPRTC_CMD(0x1d1) +#define DPRTC_CMDID_GET_FREQ_COMPENSATION DPRTC_CMD(0x1d2) +#define DPRTC_CMDID_GET_TIME DPRTC_CMD(0x1d3) +#define DPRTC_CMDID_SET_TIME DPRTC_CMD(0x1d4) +#define DPRTC_CMDID_SET_ALARM DPRTC_CMD(0x1d5) +#define DPRTC_CMDID_SET_PERIODIC_PULSE DPRTC_CMD(0x1d6) +#define DPRTC_CMDID_CLEAR_PERIODIC_PULSE DPRTC_CMD(0x1d7) +#define DPRTC_CMDID_SET_EXT_TRIGGER DPRTC_CMD(0x1d8) +#define DPRTC_CMDID_CLEAR_EXT_TRIGGER DPRTC_CMD(0x1d9) +#define DPRTC_CMDID_GET_EXT_TRIGGER_TIMESTAMP DPRTC_CMD(0x1dA) + +/* Macros for accessing command fields smaller than 1byte */ +#define DPRTC_MASK(field) \ + GENMASK(DPRTC_##field##_SHIFT + DPRTC_##field##_SIZE - 1, \ + DPRTC_##field##_SHIFT) +#define dprtc_get_field(var, field) \ + (((var) & DPRTC_MASK(field)) >> DPRTC_##field##_SHIFT) + +#pragma pack(push, 1) +struct dprtc_cmd_open { + __le32 dprtc_id; +}; + +struct dprtc_cmd_destroy { + __le32 object_id; +}; + +#define DPRTC_ENABLE_SHIFT 0 +#define DPRTC_ENABLE_SIZE 1 + +struct dprtc_rsp_is_enabled { + u8 en; +}; + +struct dprtc_cmd_get_irq { + __le32 pad; + u8 irq_index; +}; + +struct dprtc_cmd_set_irq_enable { + u8 en; + u8 pad[3]; + u8 irq_index; +}; + +struct dprtc_rsp_get_irq_enable { + u8 en; +}; + +struct dprtc_cmd_set_irq_mask { + __le32 mask; + u8 irq_index; +}; + +struct dprtc_rsp_get_irq_mask { + __le32 mask; +}; + +struct dprtc_cmd_get_irq_status { + __le32 status; + u8 irq_index; +}; + +struct dprtc_rsp_get_irq_status { + __le32 status; +}; + +struct dprtc_cmd_clear_irq_status { + __le32 status; + u8 irq_index; +}; + +struct dprtc_rsp_get_attributes { + __le32 pad; + __le32 id; +}; + +struct dprtc_cmd_set_clock_offset { + __le64 offset; +}; + +struct dprtc_get_freq_compensation { + __le32 freq_compensation; +}; + +struct dprtc_time { + __le64 time; +}; + +struct dprtc_rsp_get_api_version { + __le16 major; + __le16 minor; +}; + +#pragma pack(pop) + +#endif /* _FSL_DPRTC_CMD_H */ diff --git a/drivers/staging/fsl-dpaa2/rtc/dprtc.c b/drivers/staging/fsl-dpaa2/rtc/dprtc.c new file mode 100644 index 000000000000..68ae6ffefbf5 --- /dev/null +++ b/drivers/staging/fsl-dpaa2/rtc/dprtc.c @@ -0,0 +1,701 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright 2013-2016 Freescale Semiconductor Inc. + * Copyright 2016-2018 NXP + */ + +#include <linux/fsl/mc.h> + +#include "dprtc.h" +#include "dprtc-cmd.h" + +/** + * dprtc_open() - Open a control session for the specified object. + * @mc_io: Pointer to MC portal's I/O object + * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' + * @dprtc_id: DPRTC unique ID + * @token: Returned token; use in subsequent API calls + * + * This function can be used to open a control session for an + * already created object; an object may have been declared in + * the DPL or by calling the dprtc_create function. + * This function returns a unique authentication token, + * associated with the specific object ID and the specific MC + * portal; this token must be used in all subsequent commands for + * this specific object + * + * Return: '0' on Success; Error code otherwise. + */ +int dprtc_open(struct fsl_mc_io *mc_io, + u32 cmd_flags, + int dprtc_id, + u16 *token) +{ + struct dprtc_cmd_open *cmd_params; + struct fsl_mc_command cmd = { 0 }; + int err; + + cmd.header = mc_encode_cmd_header(DPRTC_CMDID_OPEN, + cmd_flags, + 0); + cmd_params = (struct dprtc_cmd_open *)cmd.params; + cmd_params->dprtc_id = cpu_to_le32(dprtc_id); + + err = mc_send_command(mc_io, &cmd); + if (err) + return err; + + *token = mc_cmd_hdr_read_token(&cmd); + + return 0; +} + +/** + * dprtc_close() - Close the control session of the object + * @mc_io: Pointer to MC portal's I/O object + * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' + * @token: Token of DPRTC object + * + * After this function is called, no further operations are + * allowed on the object without opening a new control session. + * + * Return: '0' on Success; Error code otherwise. + */ +int dprtc_close(struct fsl_mc_io *mc_io, + u32 cmd_flags, + u16 token) +{ + struct fsl_mc_command cmd = { 0 }; + + cmd.header = mc_encode_cmd_header(DPRTC_CMDID_CLOSE, cmd_flags, + token); + + return mc_send_command(mc_io, &cmd); +} + +/** + * dprtc_create() - Create the DPRTC object. + * @mc_io: Pointer to MC portal's I/O object + * @dprc_token: Parent container token; '0' for default container + * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' + * @cfg: Configuration structure + * @obj_id: Returned object id + * + * Create the DPRTC object, allocate required resources and + * perform required initialization. + * + * The function accepts an authentication token of a parent + * container that this object should be assigned to. The token + * can be '0' so the object will be assigned to the default container. + * The newly created object can be opened with the returned + * object id and using the container's associated tokens and MC portals. + * + * Return: '0' on Success; Error code otherwise. + */ +int dprtc_create(struct fsl_mc_io *mc_io, + u16 dprc_token, + u32 cmd_flags, + const struct dprtc_cfg *cfg, + u32 *obj_id) +{ + struct fsl_mc_command cmd = { 0 }; + int err; + + cmd.header = mc_encode_cmd_header(DPRTC_CMDID_CREATE, + cmd_flags, + dprc_token); + + err = mc_send_command(mc_io, &cmd); + if (err) + return err; + + *obj_id = mc_cmd_read_object_id(&cmd); + + return 0; +} + +/** + * dprtc_destroy() - Destroy the DPRTC object and release all its resources. + * @mc_io: Pointer to MC portal's I/O object + * @dprc_token: Parent container token; '0' for default container + * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' + * @object_id: The object id; it must be a valid id within the container that + * created this object; + * + * The function accepts the authentication token of the parent container that + * created the object (not the one that currently owns the object). The object + * is searched within parent using the provided 'object_id'. + * All tokens to the object must be closed before calling destroy. + * + * Return: '0' on Success; error code otherwise. + */ +int dprtc_destroy(struct fsl_mc_io *mc_io, + u16 dprc_token, + u32 cmd_flags, + u32 object_id) +{ + struct dprtc_cmd_destroy *cmd_params; + struct fsl_mc_command cmd = { 0 }; + + cmd.header = mc_encode_cmd_header(DPRTC_CMDID_DESTROY, + cmd_flags, + dprc_token); + cmd_params = (struct dprtc_cmd_destroy *)cmd.params; + cmd_params->object_id = cpu_to_le32(object_id); + + return mc_send_command(mc_io, &cmd); +} + +/** + * dprtc_enable() - Enable the DPRTC. + * @mc_io: Pointer to MC portal's I/O object + * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' + * @token: Token of DPRTC object + * + * Return: '0' on Success; Error code otherwise. + */ +int dprtc_enable(struct fsl_mc_io *mc_io, + u32 cmd_flags, + u16 token) +{ + struct fsl_mc_command cmd = { 0 }; + + cmd.header = mc_encode_cmd_header(DPRTC_CMDID_ENABLE, cmd_flags, + token); + + return mc_send_command(mc_io, &cmd); +} + +/** + * dprtc_disable() - Disable the DPRTC. + * @mc_io: Pointer to MC portal's I/O object + * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' + * @token: Token of DPRTC object + * + * Return: '0' on Success; Error code otherwise. + */ +int dprtc_disable(struct fsl_mc_io *mc_io, + u32 cmd_flags, + u16 token) +{ + struct fsl_mc_command cmd = { 0 }; + + cmd.header = mc_encode_cmd_header(DPRTC_CMDID_DISABLE, + cmd_flags, + token); + + return mc_send_command(mc_io, &cmd); +} + +/** + * dprtc_is_enabled() - Check if the DPRTC is enabled. + * @mc_io: Pointer to MC portal's I/O object + * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' + * @token: Token of DPRTC object + * @en: Returns '1' if object is enabled; '0' otherwise + * + * Return: '0' on Success; Error code otherwise. + */ +int dprtc_is_enabled(struct fsl_mc_io *mc_io, + u32 cmd_flags, + u16 token, + int *en) +{ + struct dprtc_rsp_is_enabled *rsp_params; + struct fsl_mc_command cmd = { 0 }; + int err; + + cmd.header = mc_encode_cmd_header(DPRTC_CMDID_IS_ENABLED, cmd_flags, + token); + + err = mc_send_command(mc_io, &cmd); + if (err) + return err; + + rsp_params = (struct dprtc_rsp_is_enabled *)cmd.params; + *en = dprtc_get_field(rsp_params->en, ENABLE); + + return 0; +} + +/** + * dprtc_reset() - Reset the DPRTC, returns the object to initial state. + * @mc_io: Pointer to MC portal's I/O object + * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' + * @token: Token of DPRTC object + * + * Return: '0' on Success; Error code otherwise. + */ +int dprtc_reset(struct fsl_mc_io *mc_io, + u32 cmd_flags, + u16 token) +{ + struct fsl_mc_command cmd = { 0 }; + + cmd.header = mc_encode_cmd_header(DPRTC_CMDID_RESET, + cmd_flags, + token); + + return mc_send_command(mc_io, &cmd); +} + +/** + * dprtc_set_irq_enable() - Set overall interrupt state. + * @mc_io: Pointer to MC portal's I/O object + * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' + * @token: Token of DPRTC object + * @irq_index: The interrupt index to configure + * @en: Interrupt state - enable = 1, disable = 0 + * + * Allows GPP software to control when interrupts are generated. + * Each interrupt can have up to 32 causes. The enable/disable control's the + * overall interrupt state. if the interrupt is disabled no causes will cause + * an interrupt. + * + * Return: '0' on Success; Error code otherwise. + */ +int dprtc_set_irq_enable(struct fsl_mc_io *mc_io, + u32 cmd_flags, + u16 token, + u8 irq_index, + u8 en) +{ + struct dprtc_cmd_set_irq_enable *cmd_params; + struct fsl_mc_command cmd = { 0 }; + + cmd.header = mc_encode_cmd_header(DPRTC_CMDID_SET_IRQ_ENABLE, + cmd_flags, + token); + cmd_params = (struct dprtc_cmd_set_irq_enable *)cmd.params; + cmd_params->irq_index = irq_index; + cmd_params->en = en; + + return mc_send_command(mc_io, &cmd); +} + +/** + * dprtc_get_irq_enable() - Get overall interrupt state + * @mc_io: Pointer to MC portal's I/O object + * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' + * @token: Token of DPRTC object + * @irq_index: The interrupt index to configure + * @en: Returned interrupt state - enable = 1, disable = 0 + * + * Return: '0' on Success; Error code otherwise. + */ +int dprtc_get_irq_enable(struct fsl_mc_io *mc_io, + u32 cmd_flags, + u16 token, + u8 irq_index, + u8 *en) +{ + struct dprtc_rsp_get_irq_enable *rsp_params; + struct dprtc_cmd_get_irq *cmd_params; + struct fsl_mc_command cmd = { 0 }; + int err; + + cmd.header = mc_encode_cmd_header(DPRTC_CMDID_GET_IRQ_ENABLE, + cmd_flags, + token); + cmd_params = (struct dprtc_cmd_get_irq *)cmd.params; + cmd_params->irq_index = irq_index; + + err = mc_send_command(mc_io, &cmd); + if (err) + return err; + + rsp_params = (struct dprtc_rsp_get_irq_enable *)cmd.params; + *en = rsp_params->en; + + return 0; +} + +/** + * dprtc_set_irq_mask() - Set interrupt mask. + * @mc_io: Pointer to MC portal's I/O object + * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' + * @token: Token of DPRTC object + * @irq_index: The interrupt index to configure + * @mask: Event mask to trigger interrupt; + * each bit: + * 0 = ignore event + * 1 = consider event for asserting IRQ + * + * Every interrupt can have up to 32 causes and the interrupt model supports + * masking/unmasking each cause independently + * + * Return: '0' on Success; Error code otherwise. + */ +int dprtc_set_irq_mask(struct fsl_mc_io *mc_io, + u32 cmd_flags, + u16 token, + u8 irq_index, + u32 mask) +{ + struct dprtc_cmd_set_irq_mask *cmd_params; + struct fsl_mc_command cmd = { 0 }; + + cmd.header = mc_encode_cmd_header(DPRTC_CMDID_SET_IRQ_MASK, + cmd_flags, + token); + cmd_params = (struct dprtc_cmd_set_irq_mask *)cmd.params; + cmd_params->mask = cpu_to_le32(mask); + cmd_params->irq_index = irq_index; + + return mc_send_command(mc_io, &cmd); +} + +/** + * dprtc_get_irq_mask() - Get interrupt mask. + * @mc_io: Pointer to MC portal's I/O object + * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' + * @token: Token of DPRTC object + * @irq_index: The interrupt index to configure + * @mask: Returned event mask to trigger interrupt + * + * Every interrupt can have up to 32 causes and the interrupt model supports + * masking/unmasking each cause independently + * + * Return: '0' on Success; Error code otherwise. + */ +int dprtc_get_irq_mask(struct fsl_mc_io *mc_io, + u32 cmd_flags, + u16 token, + u8 irq_index, + u32 *mask) +{ + struct dprtc_rsp_get_irq_mask *rsp_params; + struct dprtc_cmd_get_irq *cmd_params; + struct fsl_mc_command cmd = { 0 }; + int err; + + cmd.header = mc_encode_cmd_header(DPRTC_CMDID_GET_IRQ_MASK, + cmd_flags, + token); + cmd_params = (struct dprtc_cmd_get_irq *)cmd.params; + cmd_params->irq_index = irq_index; + + err = mc_send_command(mc_io, &cmd); + if (err) + return err; + + rsp_params = (struct dprtc_rsp_get_irq_mask *)cmd.params; + *mask = le32_to_cpu(rsp_params->mask); + + return 0; +} + +/** + * dprtc_get_irq_status() - Get the current status of any pending interrupts. + * + * @mc_io: Pointer to MC portal's I/O object + * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' + * @token: Token of DPRTC object + * @irq_index: The interrupt index to configure + * @status: Returned interrupts status - one bit per cause: + * 0 = no interrupt pending + * 1 = interrupt pending + * + * Return: '0' on Success; Error code otherwise. + */ +int dprtc_get_irq_status(struct fsl_mc_io *mc_io, + u32 cmd_flags, + u16 token, + u8 irq_index, + u32 *status) +{ + struct dprtc_cmd_get_irq_status *cmd_params; + struct dprtc_rsp_get_irq_status *rsp_params; + struct fsl_mc_command cmd = { 0 }; + int err; + + cmd.header = mc_encode_cmd_header(DPRTC_CMDID_GET_IRQ_STATUS, + cmd_flags, + token); + cmd_params = (struct dprtc_cmd_get_irq_status *)cmd.params; + cmd_params->status = cpu_to_le32(*status); + cmd_params->irq_index = irq_index; + + err = mc_send_command(mc_io, &cmd); + if (err) + return err; + + rsp_params = (struct dprtc_rsp_get_irq_status *)cmd.params; + *status = le32_to_cpu(rsp_params->status); + + return 0; +} + +/** + * dprtc_clear_irq_status() - Clear a pending interrupt's status + * + * @mc_io: Pointer to MC portal's I/O object + * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' + * @token: Token of DPRTC object + * @irq_index: The interrupt index to configure + * @status: Bits to clear (W1C) - one bit per cause: + * 0 = don't change + * 1 = clear status bit + * + * Return: '0' on Success; Error code otherwise. + */ +int dprtc_clear_irq_status(struct fsl_mc_io *mc_io, + u32 cmd_flags, + u16 token, + u8 irq_index, + u32 status) +{ + struct dprtc_cmd_clear_irq_status *cmd_params; + struct fsl_mc_command cmd = { 0 }; + + cmd.header = mc_encode_cmd_header(DPRTC_CMDID_CLEAR_IRQ_STATUS, + cmd_flags, + token); + cmd_params = (struct dprtc_cmd_clear_irq_status *)cmd.params; + cmd_params->irq_index = irq_index; + cmd_params->status = cpu_to_le32(status); + + return mc_send_command(mc_io, &cmd); +} + +/** + * dprtc_get_attributes - Retrieve DPRTC attributes. + * + * @mc_io: Pointer to MC portal's I/O object + * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' + * @token: Token of DPRTC object + * @attr: Returned object's attributes + * + * Return: '0' on Success; Error code otherwise. + */ +int dprtc_get_attributes(struct fsl_mc_io *mc_io, + u32 cmd_flags, + u16 token, + struct dprtc_attr *attr) +{ + struct dprtc_rsp_get_attributes *rsp_params; + struct fsl_mc_command cmd = { 0 }; + int err; + + cmd.header = mc_encode_cmd_header(DPRTC_CMDID_GET_ATTR, + cmd_flags, + token); + + err = mc_send_command(mc_io, &cmd); + if (err) + return err; + + rsp_params = (struct dprtc_rsp_get_attributes *)cmd.params; + attr->id = le32_to_cpu(rsp_params->id); + + return 0; +} + +/** + * dprtc_set_clock_offset() - Sets the clock's offset + * (usually relative to another clock). + * + * @mc_io: Pointer to MC portal's I/O object + * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' + * @token: Token of DPRTC object + * @offset: New clock offset (in nanoseconds). + * + * Return: '0' on Success; Error code otherwise. + */ +int dprtc_set_clock_offset(struct fsl_mc_io *mc_io, + u32 cmd_flags, + u16 token, + int64_t offset) +{ + struct dprtc_cmd_set_clock_offset *cmd_params; + struct fsl_mc_command cmd = { 0 }; + + cmd.header = mc_encode_cmd_header(DPRTC_CMDID_SET_CLOCK_OFFSET, + cmd_flags, + token); + cmd_params = (struct dprtc_cmd_set_clock_offset *)cmd.params; + cmd_params->offset = cpu_to_le64(offset); + + return mc_send_command(mc_io, &cmd); +} + +/** + * dprtc_set_freq_compensation() - Sets a new frequency compensation value. + * + * @mc_io: Pointer to MC portal's I/O object + * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' + * @token: Token of DPRTC object + * @freq_compensation: The new frequency compensation value to set. + * + * Return: '0' on Success; Error code otherwise. + */ +int dprtc_set_freq_compensation(struct fsl_mc_io *mc_io, + u32 cmd_flags, + u16 token, + u32 freq_compensation) +{ + struct dprtc_get_freq_compensation *cmd_params; + struct fsl_mc_command cmd = { 0 }; + + cmd.header = mc_encode_cmd_header(DPRTC_CMDID_SET_FREQ_COMPENSATION, + cmd_flags, + token); + cmd_params = (struct dprtc_get_freq_compensation *)cmd.params; + cmd_params->freq_compensation = cpu_to_le32(freq_compensation); + + return mc_send_command(mc_io, &cmd); +} + +/** + * dprtc_get_freq_compensation() - Retrieves the frequency compensation value + * + * @mc_io: Pointer to MC portal's I/O object + * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' + * @token: Token of DPRTC object + * @freq_compensation: Frequency compensation value + * + * Return: '0' on Success; Error code otherwise. + */ +int dprtc_get_freq_compensation(struct fsl_mc_io *mc_io, + u32 cmd_flags, + u16 token, + u32 *freq_compensation) +{ + struct dprtc_get_freq_compensation *rsp_params; + struct fsl_mc_command cmd = { 0 }; + int err; + + cmd.header = mc_encode_cmd_header(DPRTC_CMDID_GET_FREQ_COMPENSATION, + cmd_flags, + token); + + err = mc_send_command(mc_io, &cmd); + if (err) + return err; + + rsp_params = (struct dprtc_get_freq_compensation *)cmd.params; + *freq_compensation = le32_to_cpu(rsp_params->freq_compensation); + + return 0; +} + +/** + * dprtc_get_time() - Returns the current RTC time. + * + * @mc_io: Pointer to MC portal's I/O object + * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' + * @token: Token of DPRTC object + * @time: Current RTC time. + * + * Return: '0' on Success; Error code otherwise. + */ +int dprtc_get_time(struct fsl_mc_io *mc_io, + u32 cmd_flags, + u16 token, + uint64_t *time) +{ + struct dprtc_time *rsp_params; + struct fsl_mc_command cmd = { 0 }; + int err; + + cmd.header = mc_encode_cmd_header(DPRTC_CMDID_GET_TIME, + cmd_flags, + token); + + err = mc_send_command(mc_io, &cmd); + if (err) + return err; + + rsp_params = (struct dprtc_time *)cmd.params; + *time = le64_to_cpu(rsp_params->time); + + return 0; +} + +/** + * dprtc_set_time() - Updates current RTC time. + * + * @mc_io: Pointer to MC portal's I/O object + * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' + * @token: Token of DPRTC object + * @time: New RTC time. + * + * Return: '0' on Success; Error code otherwise. + */ +int dprtc_set_time(struct fsl_mc_io *mc_io, + u32 cmd_flags, + u16 token, + uint64_t time) +{ + struct dprtc_time *cmd_params; + struct fsl_mc_command cmd = { 0 }; + + cmd.header = mc_encode_cmd_header(DPRTC_CMDID_SET_TIME, + cmd_flags, + token); + cmd_params = (struct dprtc_time *)cmd.params; + cmd_params->time = cpu_to_le64(time); + + return mc_send_command(mc_io, &cmd); +} + +/** + * dprtc_set_alarm() - Defines and sets alarm. + * + * @mc_io: Pointer to MC portal's I/O object + * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' + * @token: Token of DPRTC object + * @time: In nanoseconds, the time when the alarm + * should go off - must be a multiple of + * 1 microsecond + * + * Return: '0' on Success; Error code otherwise. + */ +int dprtc_set_alarm(struct fsl_mc_io *mc_io, + u32 cmd_flags, + u16 token, uint64_t time) +{ + struct dprtc_time *cmd_params; + struct fsl_mc_command cmd = { 0 }; + + cmd.header = mc_encode_cmd_header(DPRTC_CMDID_SET_ALARM, + cmd_flags, + token); + cmd_params = (struct dprtc_time *)cmd.params; + cmd_params->time = cpu_to_le64(time); + + return mc_send_command(mc_io, &cmd); +} + +/** + * dprtc_get_api_version() - Get Data Path Real Time Counter API version + * @mc_io: Pointer to MC portal's I/O object + * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' + * @major_ver: Major version of data path real time counter API + * @minor_ver: Minor version of data path real time counter API + * + * Return: '0' on Success; Error code otherwise. + */ +int dprtc_get_api_version(struct fsl_mc_io *mc_io, + u32 cmd_flags, + u16 *major_ver, + u16 *minor_ver) +{ + struct dprtc_rsp_get_api_version *rsp_params; + struct fsl_mc_command cmd = { 0 }; + int err; + + cmd.header = mc_encode_cmd_header(DPRTC_CMDID_GET_API_VERSION, + cmd_flags, + 0); + + err = mc_send_command(mc_io, &cmd); + if (err) + return err; + + rsp_params = (struct dprtc_rsp_get_api_version *)cmd.params; + *major_ver = le16_to_cpu(rsp_params->major); + *minor_ver = le16_to_cpu(rsp_params->minor); + + return 0; +} diff --git a/drivers/staging/fsl-dpaa2/rtc/dprtc.h b/drivers/staging/fsl-dpaa2/rtc/dprtc.h new file mode 100644 index 000000000000..08f7c7bebbca --- /dev/null +++ b/drivers/staging/fsl-dpaa2/rtc/dprtc.h @@ -0,0 +1,164 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright 2013-2016 Freescale Semiconductor Inc. + * Copyright 2016-2018 NXP + */ + +#ifndef __FSL_DPRTC_H +#define __FSL_DPRTC_H + +/* Data Path Real Time Counter API + * Contains initialization APIs and runtime control APIs for RTC + */ + +struct fsl_mc_io; + +/** + * Number of irq's + */ +#define DPRTC_MAX_IRQ_NUM 1 +#define DPRTC_IRQ_INDEX 0 + +/** + * Interrupt event masks: + */ + +/** + * Interrupt event mask indicating alarm event had occurred + */ +#define DPRTC_EVENT_ALARM 0x40000000 +/** + * Interrupt event mask indicating periodic pulse event had occurred + */ +#define DPRTC_EVENT_PPS 0x08000000 + +int dprtc_open(struct fsl_mc_io *mc_io, + u32 cmd_flags, + int dprtc_id, + u16 *token); + +int dprtc_close(struct fsl_mc_io *mc_io, + u32 cmd_flags, + u16 token); + +/** + * struct dprtc_cfg - Structure representing DPRTC configuration + * @options: place holder + */ +struct dprtc_cfg { + u32 options; +}; + +int dprtc_create(struct fsl_mc_io *mc_io, + u16 dprc_token, + u32 cmd_flags, + const struct dprtc_cfg *cfg, + u32 *obj_id); + +int dprtc_destroy(struct fsl_mc_io *mc_io, + u16 dprc_token, + u32 cmd_flags, + u32 object_id); + +int dprtc_enable(struct fsl_mc_io *mc_io, + u32 cmd_flags, + u16 token); + +int dprtc_disable(struct fsl_mc_io *mc_io, + u32 cmd_flags, + u16 token); + +int dprtc_is_enabled(struct fsl_mc_io *mc_io, + u32 cmd_flags, + u16 token, + int *en); + +int dprtc_reset(struct fsl_mc_io *mc_io, + u32 cmd_flags, + u16 token); + +int dprtc_set_clock_offset(struct fsl_mc_io *mc_io, + u32 cmd_flags, + u16 token, + int64_t offset); + +int dprtc_set_freq_compensation(struct fsl_mc_io *mc_io, + u32 cmd_flags, + u16 token, + u32 freq_compensation); + +int dprtc_get_freq_compensation(struct fsl_mc_io *mc_io, + u32 cmd_flags, + u16 token, + u32 *freq_compensation); + +int dprtc_get_time(struct fsl_mc_io *mc_io, + u32 cmd_flags, + u16 token, + uint64_t *time); + +int dprtc_set_time(struct fsl_mc_io *mc_io, + u32 cmd_flags, + u16 token, + uint64_t time); + +int dprtc_set_alarm(struct fsl_mc_io *mc_io, + u32 cmd_flags, + u16 token, + uint64_t time); + +int dprtc_set_irq_enable(struct fsl_mc_io *mc_io, + u32 cmd_flags, + u16 token, + u8 irq_index, + u8 en); + +int dprtc_get_irq_enable(struct fsl_mc_io *mc_io, + u32 cmd_flags, + u16 token, + u8 irq_index, + u8 *en); + +int dprtc_set_irq_mask(struct fsl_mc_io *mc_io, + u32 cmd_flags, + u16 token, + u8 irq_index, + u32 mask); + +int dprtc_get_irq_mask(struct fsl_mc_io *mc_io, + u32 cmd_flags, + u16 token, + u8 irq_index, + u32 *mask); + +int dprtc_get_irq_status(struct fsl_mc_io *mc_io, + u32 cmd_flags, + u16 token, + u8 irq_index, + u32 *status); + +int dprtc_clear_irq_status(struct fsl_mc_io *mc_io, + u32 cmd_flags, + u16 token, + u8 irq_index, + u32 status); + +/** + * struct dprtc_attr - Structure representing DPRTC attributes + * @id: DPRTC object ID + */ +struct dprtc_attr { + int id; +}; + +int dprtc_get_attributes(struct fsl_mc_io *mc_io, + u32 cmd_flags, + u16 token, + struct dprtc_attr *attr); + +int dprtc_get_api_version(struct fsl_mc_io *mc_io, + u32 cmd_flags, + u16 *major_ver, + u16 *minor_ver); + +#endif /* __FSL_DPRTC_H */ diff --git a/drivers/staging/fsl-dpaa2/rtc/rtc.c b/drivers/staging/fsl-dpaa2/rtc/rtc.c new file mode 100644 index 000000000000..0d52cb85441f --- /dev/null +++ b/drivers/staging/fsl-dpaa2/rtc/rtc.c @@ -0,0 +1,229 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright 2013-2016 Freescale Semiconductor Inc. + * Copyright 2016-2018 NXP + */ + +#include <linux/module.h> +#include <linux/slab.h> +#include <linux/ptp_clock_kernel.h> +#include <linux/fsl/mc.h> + +#include "rtc.h" + +struct ptp_dpaa2_priv { + struct fsl_mc_device *rtc_mc_dev; + struct ptp_clock *clock; + struct ptp_clock_info caps; + u32 freq_comp; +}; + +/* PTP clock operations */ +static int ptp_dpaa2_adjfreq(struct ptp_clock_info *ptp, s32 ppb) +{ + struct ptp_dpaa2_priv *ptp_dpaa2 = + container_of(ptp, struct ptp_dpaa2_priv, caps); + struct fsl_mc_device *mc_dev = ptp_dpaa2->rtc_mc_dev; + struct device *dev = &mc_dev->dev; + u64 adj; + u32 diff, tmr_add; + int neg_adj = 0; + int err = 0; + + if (ppb < 0) { + neg_adj = 1; + ppb = -ppb; + } + + tmr_add = ptp_dpaa2->freq_comp; + adj = tmr_add; + adj *= ppb; + diff = div_u64(adj, 1000000000ULL); + + tmr_add = neg_adj ? tmr_add - diff : tmr_add + diff; + + err = dprtc_set_freq_compensation(mc_dev->mc_io, 0, + mc_dev->mc_handle, tmr_add); + if (err) + dev_err(dev, "dprtc_set_freq_compensation err %d\n", err); + return 0; +} + +static int ptp_dpaa2_adjtime(struct ptp_clock_info *ptp, s64 delta) +{ + struct ptp_dpaa2_priv *ptp_dpaa2 = + container_of(ptp, struct ptp_dpaa2_priv, caps); + struct fsl_mc_device *mc_dev = ptp_dpaa2->rtc_mc_dev; + struct device *dev = &mc_dev->dev; + s64 now; + int err = 0; + + err = dprtc_get_time(mc_dev->mc_io, 0, mc_dev->mc_handle, &now); + if (err) { + dev_err(dev, "dprtc_get_time err %d\n", err); + return 0; + } + + now += delta; + + err = dprtc_set_time(mc_dev->mc_io, 0, mc_dev->mc_handle, now); + if (err) { + dev_err(dev, "dprtc_set_time err %d\n", err); + return 0; + } + return 0; +} + +static int ptp_dpaa2_gettime(struct ptp_clock_info *ptp, struct timespec64 *ts) +{ + struct ptp_dpaa2_priv *ptp_dpaa2 = + container_of(ptp, struct ptp_dpaa2_priv, caps); + struct fsl_mc_device *mc_dev = ptp_dpaa2->rtc_mc_dev; + struct device *dev = &mc_dev->dev; + u64 ns; + u32 remainder; + int err = 0; + + err = dprtc_get_time(mc_dev->mc_io, 0, mc_dev->mc_handle, &ns); + if (err) { + dev_err(dev, "dprtc_get_time err %d\n", err); + return 0; + } + + ts->tv_sec = div_u64_rem(ns, 1000000000, &remainder); + ts->tv_nsec = remainder; + return 0; +} + +static int ptp_dpaa2_settime(struct ptp_clock_info *ptp, + const struct timespec64 *ts) +{ + struct ptp_dpaa2_priv *ptp_dpaa2 = + container_of(ptp, struct ptp_dpaa2_priv, caps); + struct fsl_mc_device *mc_dev = ptp_dpaa2->rtc_mc_dev; + struct device *dev = &mc_dev->dev; + u64 ns; + int err = 0; + + ns = ts->tv_sec * 1000000000ULL; + ns += ts->tv_nsec; + + err = dprtc_set_time(mc_dev->mc_io, 0, mc_dev->mc_handle, ns); + if (err) + dev_err(dev, "dprtc_set_time err %d\n", err); + return 0; +} + +static struct ptp_clock_info ptp_dpaa2_caps = { + .owner = THIS_MODULE, + .name = "DPAA2 PTP Clock", + .max_adj = 512000, + .n_alarm = 2, + .n_ext_ts = 2, + .n_per_out = 3, + .n_pins = 0, + .pps = 1, + .adjfreq = ptp_dpaa2_adjfreq, + .adjtime = ptp_dpaa2_adjtime, + .gettime64 = ptp_dpaa2_gettime, + .settime64 = ptp_dpaa2_settime, +}; + +static int rtc_probe(struct fsl_mc_device *mc_dev) +{ + struct device *dev = &mc_dev->dev; + struct ptp_dpaa2_priv *ptp_dpaa2; + u32 tmr_add = 0; + int err; + + ptp_dpaa2 = kzalloc(sizeof(*ptp_dpaa2), GFP_KERNEL); + if (!ptp_dpaa2) + return -ENOMEM; + + err = fsl_mc_portal_allocate(mc_dev, 0, &mc_dev->mc_io); + if (err) { + dev_err(dev, "fsl_mc_portal_allocate err %d\n", err); + goto err_exit; + } + + err = dprtc_open(mc_dev->mc_io, 0, mc_dev->obj_desc.id, + &mc_dev->mc_handle); + if (err) { + dev_err(dev, "dprtc_open err %d\n", err); + goto err_free_mcp; + } + + ptp_dpaa2->rtc_mc_dev = mc_dev; + + err = dprtc_get_freq_compensation(mc_dev->mc_io, 0, + mc_dev->mc_handle, &tmr_add); + if (err) { + dev_err(dev, "dprtc_get_freq_compensation err %d\n", err); + goto err_close; + } + + ptp_dpaa2->freq_comp = tmr_add; + ptp_dpaa2->caps = ptp_dpaa2_caps; + + ptp_dpaa2->clock = ptp_clock_register(&ptp_dpaa2->caps, dev); + if (IS_ERR(ptp_dpaa2->clock)) { + err = PTR_ERR(ptp_dpaa2->clock); + goto err_close; + } + + dpaa2_phc_index = ptp_clock_index(ptp_dpaa2->clock); + + dev_set_drvdata(dev, ptp_dpaa2); + + return 0; + +err_close: + dprtc_close(mc_dev->mc_io, 0, mc_dev->mc_handle); +err_free_mcp: + fsl_mc_portal_free(mc_dev->mc_io); +err_exit: + kfree(ptp_dpaa2); + dev_set_drvdata(dev, NULL); + return err; +} + +static int rtc_remove(struct fsl_mc_device *mc_dev) +{ + struct ptp_dpaa2_priv *ptp_dpaa2; + struct device *dev = &mc_dev->dev; + + ptp_dpaa2 = dev_get_drvdata(dev); + ptp_clock_unregister(ptp_dpaa2->clock); + + dprtc_close(mc_dev->mc_io, 0, mc_dev->mc_handle); + fsl_mc_portal_free(mc_dev->mc_io); + + kfree(ptp_dpaa2); + dev_set_drvdata(dev, NULL); + + return 0; +} + +static const struct fsl_mc_device_id rtc_match_id_table[] = { + { + .vendor = FSL_MC_VENDOR_FREESCALE, + .obj_type = "dprtc", + }, + {} +}; +MODULE_DEVICE_TABLE(fslmc, rtc_match_id_table); + +static struct fsl_mc_driver rtc_drv = { + .driver = { + .name = KBUILD_MODNAME, + .owner = THIS_MODULE, + }, + .probe = rtc_probe, + .remove = rtc_remove, + .match_id_table = rtc_match_id_table, +}; + +module_fsl_mc_driver(rtc_drv); + +MODULE_LICENSE("GPL v2"); +MODULE_DESCRIPTION("DPAA2 PTP Clock Driver"); diff --git a/drivers/staging/fsl-dpaa2/rtc/rtc.h b/drivers/staging/fsl-dpaa2/rtc/rtc.h new file mode 100644 index 000000000000..ff2e177395d4 --- /dev/null +++ b/drivers/staging/fsl-dpaa2/rtc/rtc.h @@ -0,0 +1,14 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright 2018 NXP + */ + +#ifndef __RTC_H +#define __RTC_H + +#include "dprtc.h" +#include "dprtc-cmd.h" + +extern int dpaa2_phc_index; + +#endif |