if (felix->info->pcs_init)
                felix->info->pcs_init(ocelot, port, link_an_mode, state);
+
+       if (felix->info->port_sched_speed_set)
+               felix->info->port_sched_speed_set(ocelot, port,
+                                                 state->speed);
 }
 
 static void felix_phylink_mac_an_restart(struct dsa_switch *ds, int port)
        ocelot_port_policer_del(ocelot, port);
 }
 
+static int felix_port_setup_tc(struct dsa_switch *ds, int port,
+                              enum tc_setup_type type,
+                              void *type_data)
+{
+       struct ocelot *ocelot = ds->priv;
+       struct felix *felix = ocelot_to_felix(ocelot);
+
+       if (felix->info->port_setup_tc)
+               return felix->info->port_setup_tc(ds, port, type, type_data);
+       else
+               return -EOPNOTSUPP;
+}
+
 static const struct dsa_switch_ops felix_switch_ops = {
        .get_tag_protocol       = felix_get_tag_protocol,
        .setup                  = felix_setup,
        .cls_flower_add         = felix_cls_flower_add,
        .cls_flower_del         = felix_cls_flower_del,
        .cls_flower_stats       = felix_cls_flower_stats,
+       .port_setup_tc          = felix_port_setup_tc,
 };
 
 static struct felix_info *felix_instance_tbl[] = {
 
        ds->dev = &pdev->dev;
        ds->num_ports = felix->info->num_ports;
+       ds->num_tx_queues = felix->info->num_tx_queues;
        ds->ops = &felix_switch_ops;
        ds->priv = ocelot;
        felix->ds = ds;
 
  * Copyright 2018-2019 NXP Semiconductors
  */
 #include <linux/fsl/enetc_mdio.h>
+#include <soc/mscc/ocelot_qsys.h>
 #include <soc/mscc/ocelot_vcap.h>
+#include <soc/mscc/ocelot_ptp.h>
 #include <soc/mscc/ocelot_sys.h>
 #include <soc/mscc/ocelot.h>
+#include <net/pkt_sched.h>
 #include <linux/iopoll.h>
 #include <linux/pci.h>
 #include "felix.h"
 #define USXGMII_LPA_DUPLEX(lpa)                (((lpa) & GENMASK(12, 12)) >> 12)
 #define USXGMII_LPA_SPEED(lpa)         (((lpa) & GENMASK(11, 9)) >> 9)
 
+#define VSC9959_TAS_GCL_ENTRY_MAX      63
+
 enum usxgmii_speed {
        USXGMII_SPEED_10        = 0,
        USXGMII_SPEED_100       = 1,
        mdiobus_unregister(felix->imdio);
 }
 
+static void vsc9959_sched_speed_set(struct ocelot *ocelot, int port,
+                                   u32 speed)
+{
+       ocelot_rmw_rix(ocelot,
+                      QSYS_TAG_CONFIG_LINK_SPEED(speed),
+                      QSYS_TAG_CONFIG_LINK_SPEED_M,
+                      QSYS_TAG_CONFIG, port);
+}
+
+static void vsc9959_new_base_time(struct ocelot *ocelot, ktime_t base_time,
+                                 u64 cycle_time,
+                                 struct timespec64 *new_base_ts)
+{
+       struct timespec64 ts;
+       ktime_t new_base_time;
+       ktime_t current_time;
+
+       ocelot_ptp_gettime64(&ocelot->ptp_info, &ts);
+       current_time = timespec64_to_ktime(ts);
+       new_base_time = base_time;
+
+       if (base_time < current_time) {
+               u64 nr_of_cycles = current_time - base_time;
+
+               do_div(nr_of_cycles, cycle_time);
+               new_base_time += cycle_time * (nr_of_cycles + 1);
+       }
+
+       *new_base_ts = ktime_to_timespec64(new_base_time);
+}
+
+static u32 vsc9959_tas_read_cfg_status(struct ocelot *ocelot)
+{
+       return ocelot_read(ocelot, QSYS_TAS_PARAM_CFG_CTRL);
+}
+
+static void vsc9959_tas_gcl_set(struct ocelot *ocelot, const u32 gcl_ix,
+                               struct tc_taprio_sched_entry *entry)
+{
+       ocelot_write(ocelot,
+                    QSYS_GCL_CFG_REG_1_GCL_ENTRY_NUM(gcl_ix) |
+                    QSYS_GCL_CFG_REG_1_GATE_STATE(entry->gate_mask),
+                    QSYS_GCL_CFG_REG_1);
+       ocelot_write(ocelot, entry->interval, QSYS_GCL_CFG_REG_2);
+}
+
+static int vsc9959_qos_port_tas_set(struct ocelot *ocelot, int port,
+                                   struct tc_taprio_qopt_offload *taprio)
+{
+       struct timespec64 base_ts;
+       int ret, i;
+       u32 val;
+
+       if (!taprio->enable) {
+               ocelot_rmw_rix(ocelot,
+                              QSYS_TAG_CONFIG_INIT_GATE_STATE(0xFF),
+                              QSYS_TAG_CONFIG_ENABLE |
+                              QSYS_TAG_CONFIG_INIT_GATE_STATE_M,
+                              QSYS_TAG_CONFIG, port);
+
+               return 0;
+       }
+
+       if (taprio->cycle_time > NSEC_PER_SEC ||
+           taprio->cycle_time_extension >= NSEC_PER_SEC)
+               return -EINVAL;
+
+       if (taprio->num_entries > VSC9959_TAS_GCL_ENTRY_MAX)
+               return -ERANGE;
+
+       ocelot_rmw(ocelot, QSYS_TAS_PARAM_CFG_CTRL_PORT_NUM(port) |
+                  QSYS_TAS_PARAM_CFG_CTRL_ALWAYS_GUARD_BAND_SCH_Q,
+                  QSYS_TAS_PARAM_CFG_CTRL_PORT_NUM_M |
+                  QSYS_TAS_PARAM_CFG_CTRL_ALWAYS_GUARD_BAND_SCH_Q,
+                  QSYS_TAS_PARAM_CFG_CTRL);
+
+       /* Hardware errata -  Admin config could not be overwritten if
+        * config is pending, need reset the TAS module
+        */
+       val = ocelot_read(ocelot, QSYS_PARAM_STATUS_REG_8);
+       if (val & QSYS_PARAM_STATUS_REG_8_CONFIG_PENDING)
+               return  -EBUSY;
+
+       ocelot_rmw_rix(ocelot,
+                      QSYS_TAG_CONFIG_ENABLE |
+                      QSYS_TAG_CONFIG_INIT_GATE_STATE(0xFF) |
+                      QSYS_TAG_CONFIG_SCH_TRAFFIC_QUEUES(0xFF),
+                      QSYS_TAG_CONFIG_ENABLE |
+                      QSYS_TAG_CONFIG_INIT_GATE_STATE_M |
+                      QSYS_TAG_CONFIG_SCH_TRAFFIC_QUEUES_M,
+                      QSYS_TAG_CONFIG, port);
+
+       vsc9959_new_base_time(ocelot, taprio->base_time,
+                             taprio->cycle_time, &base_ts);
+       ocelot_write(ocelot, base_ts.tv_nsec, QSYS_PARAM_CFG_REG_1);
+       ocelot_write(ocelot, lower_32_bits(base_ts.tv_sec), QSYS_PARAM_CFG_REG_2);
+       val = upper_32_bits(base_ts.tv_sec);
+       ocelot_write(ocelot,
+                    QSYS_PARAM_CFG_REG_3_BASE_TIME_SEC_MSB(val) |
+                    QSYS_PARAM_CFG_REG_3_LIST_LENGTH(taprio->num_entries),
+                    QSYS_PARAM_CFG_REG_3);
+       ocelot_write(ocelot, taprio->cycle_time, QSYS_PARAM_CFG_REG_4);
+       ocelot_write(ocelot, taprio->cycle_time_extension, QSYS_PARAM_CFG_REG_5);
+
+       for (i = 0; i < taprio->num_entries; i++)
+               vsc9959_tas_gcl_set(ocelot, i, &taprio->entries[i]);
+
+       ocelot_rmw(ocelot, QSYS_TAS_PARAM_CFG_CTRL_CONFIG_CHANGE,
+                  QSYS_TAS_PARAM_CFG_CTRL_CONFIG_CHANGE,
+                  QSYS_TAS_PARAM_CFG_CTRL);
+
+       ret = readx_poll_timeout(vsc9959_tas_read_cfg_status, ocelot, val,
+                                !(val & QSYS_TAS_PARAM_CFG_CTRL_CONFIG_CHANGE),
+                                10, 100000);
+
+       return ret;
+}
+
+static int vsc9959_port_setup_tc(struct dsa_switch *ds, int port,
+                                enum tc_setup_type type,
+                                void *type_data)
+{
+       struct ocelot *ocelot = ds->priv;
+
+       switch (type) {
+       case TC_SETUP_QDISC_TAPRIO:
+               return vsc9959_qos_port_tas_set(ocelot, port, type_data);
+       default:
+               return -EOPNOTSUPP;
+       }
+}
+
 struct felix_info felix_info_vsc9959 = {
        .target_io_res          = vsc9959_target_io_res,
        .port_io_res            = vsc9959_port_io_res,
        .shared_queue_sz        = 128 * 1024,
        .num_mact_rows          = 2048,
        .num_ports              = 6,
+       .num_tx_queues          = FELIX_NUM_TC,
        .switch_pci_bar         = 4,
        .imdio_pci_bar          = 0,
        .mdio_bus_alloc         = vsc9959_mdio_bus_alloc,
        .pcs_an_restart         = vsc9959_pcs_an_restart,
        .pcs_link_state         = vsc9959_pcs_link_state,
        .prevalidate_phy_mode   = vsc9959_prevalidate_phy_mode,
+       .port_setup_tc          = vsc9959_port_setup_tc,
+       .port_sched_speed_set   = vsc9959_sched_speed_set,
 };