162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* Copyright (c) 2020 Facebook */ 362306a36Sopenharmony_ci 462306a36Sopenharmony_ci#include <linux/bits.h> 562306a36Sopenharmony_ci#include <linux/err.h> 662306a36Sopenharmony_ci#include <linux/kernel.h> 762306a36Sopenharmony_ci#include <linux/module.h> 862306a36Sopenharmony_ci#include <linux/debugfs.h> 962306a36Sopenharmony_ci#include <linux/init.h> 1062306a36Sopenharmony_ci#include <linux/pci.h> 1162306a36Sopenharmony_ci#include <linux/serial_8250.h> 1262306a36Sopenharmony_ci#include <linux/clkdev.h> 1362306a36Sopenharmony_ci#include <linux/clk-provider.h> 1462306a36Sopenharmony_ci#include <linux/platform_device.h> 1562306a36Sopenharmony_ci#include <linux/platform_data/i2c-xiic.h> 1662306a36Sopenharmony_ci#include <linux/platform_data/i2c-ocores.h> 1762306a36Sopenharmony_ci#include <linux/ptp_clock_kernel.h> 1862306a36Sopenharmony_ci#include <linux/spi/spi.h> 1962306a36Sopenharmony_ci#include <linux/spi/xilinx_spi.h> 2062306a36Sopenharmony_ci#include <linux/spi/altera.h> 2162306a36Sopenharmony_ci#include <net/devlink.h> 2262306a36Sopenharmony_ci#include <linux/i2c.h> 2362306a36Sopenharmony_ci#include <linux/mtd/mtd.h> 2462306a36Sopenharmony_ci#include <linux/nvmem-consumer.h> 2562306a36Sopenharmony_ci#include <linux/crc16.h> 2662306a36Sopenharmony_ci 2762306a36Sopenharmony_ci#define PCI_VENDOR_ID_FACEBOOK 0x1d9b 2862306a36Sopenharmony_ci#define PCI_DEVICE_ID_FACEBOOK_TIMECARD 0x0400 2962306a36Sopenharmony_ci 3062306a36Sopenharmony_ci#define PCI_VENDOR_ID_CELESTICA 0x18d4 3162306a36Sopenharmony_ci#define PCI_DEVICE_ID_CELESTICA_TIMECARD 0x1008 3262306a36Sopenharmony_ci 3362306a36Sopenharmony_ci#define PCI_VENDOR_ID_OROLIA 0x1ad7 3462306a36Sopenharmony_ci#define PCI_DEVICE_ID_OROLIA_ARTCARD 0xa000 3562306a36Sopenharmony_ci 3662306a36Sopenharmony_cistatic struct class timecard_class = { 3762306a36Sopenharmony_ci .name = "timecard", 3862306a36Sopenharmony_ci}; 3962306a36Sopenharmony_ci 4062306a36Sopenharmony_cistruct ocp_reg { 4162306a36Sopenharmony_ci u32 ctrl; 4262306a36Sopenharmony_ci u32 status; 4362306a36Sopenharmony_ci u32 select; 4462306a36Sopenharmony_ci u32 version; 4562306a36Sopenharmony_ci u32 time_ns; 4662306a36Sopenharmony_ci u32 time_sec; 4762306a36Sopenharmony_ci u32 __pad0[2]; 4862306a36Sopenharmony_ci u32 adjust_ns; 4962306a36Sopenharmony_ci u32 adjust_sec; 5062306a36Sopenharmony_ci u32 __pad1[2]; 5162306a36Sopenharmony_ci u32 offset_ns; 5262306a36Sopenharmony_ci u32 offset_window_ns; 5362306a36Sopenharmony_ci u32 __pad2[2]; 5462306a36Sopenharmony_ci u32 drift_ns; 5562306a36Sopenharmony_ci u32 drift_window_ns; 5662306a36Sopenharmony_ci u32 __pad3[6]; 5762306a36Sopenharmony_ci u32 servo_offset_p; 5862306a36Sopenharmony_ci u32 servo_offset_i; 5962306a36Sopenharmony_ci u32 servo_drift_p; 6062306a36Sopenharmony_ci u32 servo_drift_i; 6162306a36Sopenharmony_ci u32 status_offset; 6262306a36Sopenharmony_ci u32 status_drift; 6362306a36Sopenharmony_ci}; 6462306a36Sopenharmony_ci 6562306a36Sopenharmony_ci#define OCP_CTRL_ENABLE BIT(0) 6662306a36Sopenharmony_ci#define OCP_CTRL_ADJUST_TIME BIT(1) 6762306a36Sopenharmony_ci#define OCP_CTRL_ADJUST_OFFSET BIT(2) 6862306a36Sopenharmony_ci#define OCP_CTRL_ADJUST_DRIFT BIT(3) 6962306a36Sopenharmony_ci#define OCP_CTRL_ADJUST_SERVO BIT(8) 7062306a36Sopenharmony_ci#define OCP_CTRL_READ_TIME_REQ BIT(30) 7162306a36Sopenharmony_ci#define OCP_CTRL_READ_TIME_DONE BIT(31) 7262306a36Sopenharmony_ci 7362306a36Sopenharmony_ci#define OCP_STATUS_IN_SYNC BIT(0) 7462306a36Sopenharmony_ci#define OCP_STATUS_IN_HOLDOVER BIT(1) 7562306a36Sopenharmony_ci 7662306a36Sopenharmony_ci#define OCP_SELECT_CLK_NONE 0 7762306a36Sopenharmony_ci#define OCP_SELECT_CLK_REG 0xfe 7862306a36Sopenharmony_ci 7962306a36Sopenharmony_cistruct tod_reg { 8062306a36Sopenharmony_ci u32 ctrl; 8162306a36Sopenharmony_ci u32 status; 8262306a36Sopenharmony_ci u32 uart_polarity; 8362306a36Sopenharmony_ci u32 version; 8462306a36Sopenharmony_ci u32 adj_sec; 8562306a36Sopenharmony_ci u32 __pad0[3]; 8662306a36Sopenharmony_ci u32 uart_baud; 8762306a36Sopenharmony_ci u32 __pad1[3]; 8862306a36Sopenharmony_ci u32 utc_status; 8962306a36Sopenharmony_ci u32 leap; 9062306a36Sopenharmony_ci}; 9162306a36Sopenharmony_ci 9262306a36Sopenharmony_ci#define TOD_CTRL_PROTOCOL BIT(28) 9362306a36Sopenharmony_ci#define TOD_CTRL_DISABLE_FMT_A BIT(17) 9462306a36Sopenharmony_ci#define TOD_CTRL_DISABLE_FMT_B BIT(16) 9562306a36Sopenharmony_ci#define TOD_CTRL_ENABLE BIT(0) 9662306a36Sopenharmony_ci#define TOD_CTRL_GNSS_MASK GENMASK(3, 0) 9762306a36Sopenharmony_ci#define TOD_CTRL_GNSS_SHIFT 24 9862306a36Sopenharmony_ci 9962306a36Sopenharmony_ci#define TOD_STATUS_UTC_MASK GENMASK(7, 0) 10062306a36Sopenharmony_ci#define TOD_STATUS_UTC_VALID BIT(8) 10162306a36Sopenharmony_ci#define TOD_STATUS_LEAP_ANNOUNCE BIT(12) 10262306a36Sopenharmony_ci#define TOD_STATUS_LEAP_VALID BIT(16) 10362306a36Sopenharmony_ci 10462306a36Sopenharmony_cistruct ts_reg { 10562306a36Sopenharmony_ci u32 enable; 10662306a36Sopenharmony_ci u32 error; 10762306a36Sopenharmony_ci u32 polarity; 10862306a36Sopenharmony_ci u32 version; 10962306a36Sopenharmony_ci u32 __pad0[4]; 11062306a36Sopenharmony_ci u32 cable_delay; 11162306a36Sopenharmony_ci u32 __pad1[3]; 11262306a36Sopenharmony_ci u32 intr; 11362306a36Sopenharmony_ci u32 intr_mask; 11462306a36Sopenharmony_ci u32 event_count; 11562306a36Sopenharmony_ci u32 __pad2[1]; 11662306a36Sopenharmony_ci u32 ts_count; 11762306a36Sopenharmony_ci u32 time_ns; 11862306a36Sopenharmony_ci u32 time_sec; 11962306a36Sopenharmony_ci u32 data_width; 12062306a36Sopenharmony_ci u32 data; 12162306a36Sopenharmony_ci}; 12262306a36Sopenharmony_ci 12362306a36Sopenharmony_cistruct pps_reg { 12462306a36Sopenharmony_ci u32 ctrl; 12562306a36Sopenharmony_ci u32 status; 12662306a36Sopenharmony_ci u32 __pad0[6]; 12762306a36Sopenharmony_ci u32 cable_delay; 12862306a36Sopenharmony_ci}; 12962306a36Sopenharmony_ci 13062306a36Sopenharmony_ci#define PPS_STATUS_FILTER_ERR BIT(0) 13162306a36Sopenharmony_ci#define PPS_STATUS_SUPERV_ERR BIT(1) 13262306a36Sopenharmony_ci 13362306a36Sopenharmony_cistruct img_reg { 13462306a36Sopenharmony_ci u32 version; 13562306a36Sopenharmony_ci}; 13662306a36Sopenharmony_ci 13762306a36Sopenharmony_cistruct gpio_reg { 13862306a36Sopenharmony_ci u32 gpio1; 13962306a36Sopenharmony_ci u32 __pad0; 14062306a36Sopenharmony_ci u32 gpio2; 14162306a36Sopenharmony_ci u32 __pad1; 14262306a36Sopenharmony_ci}; 14362306a36Sopenharmony_ci 14462306a36Sopenharmony_cistruct irig_master_reg { 14562306a36Sopenharmony_ci u32 ctrl; 14662306a36Sopenharmony_ci u32 status; 14762306a36Sopenharmony_ci u32 __pad0; 14862306a36Sopenharmony_ci u32 version; 14962306a36Sopenharmony_ci u32 adj_sec; 15062306a36Sopenharmony_ci u32 mode_ctrl; 15162306a36Sopenharmony_ci}; 15262306a36Sopenharmony_ci 15362306a36Sopenharmony_ci#define IRIG_M_CTRL_ENABLE BIT(0) 15462306a36Sopenharmony_ci 15562306a36Sopenharmony_cistruct irig_slave_reg { 15662306a36Sopenharmony_ci u32 ctrl; 15762306a36Sopenharmony_ci u32 status; 15862306a36Sopenharmony_ci u32 __pad0; 15962306a36Sopenharmony_ci u32 version; 16062306a36Sopenharmony_ci u32 adj_sec; 16162306a36Sopenharmony_ci u32 mode_ctrl; 16262306a36Sopenharmony_ci}; 16362306a36Sopenharmony_ci 16462306a36Sopenharmony_ci#define IRIG_S_CTRL_ENABLE BIT(0) 16562306a36Sopenharmony_ci 16662306a36Sopenharmony_cistruct dcf_master_reg { 16762306a36Sopenharmony_ci u32 ctrl; 16862306a36Sopenharmony_ci u32 status; 16962306a36Sopenharmony_ci u32 __pad0; 17062306a36Sopenharmony_ci u32 version; 17162306a36Sopenharmony_ci u32 adj_sec; 17262306a36Sopenharmony_ci}; 17362306a36Sopenharmony_ci 17462306a36Sopenharmony_ci#define DCF_M_CTRL_ENABLE BIT(0) 17562306a36Sopenharmony_ci 17662306a36Sopenharmony_cistruct dcf_slave_reg { 17762306a36Sopenharmony_ci u32 ctrl; 17862306a36Sopenharmony_ci u32 status; 17962306a36Sopenharmony_ci u32 __pad0; 18062306a36Sopenharmony_ci u32 version; 18162306a36Sopenharmony_ci u32 adj_sec; 18262306a36Sopenharmony_ci}; 18362306a36Sopenharmony_ci 18462306a36Sopenharmony_ci#define DCF_S_CTRL_ENABLE BIT(0) 18562306a36Sopenharmony_ci 18662306a36Sopenharmony_cistruct signal_reg { 18762306a36Sopenharmony_ci u32 enable; 18862306a36Sopenharmony_ci u32 status; 18962306a36Sopenharmony_ci u32 polarity; 19062306a36Sopenharmony_ci u32 version; 19162306a36Sopenharmony_ci u32 __pad0[4]; 19262306a36Sopenharmony_ci u32 cable_delay; 19362306a36Sopenharmony_ci u32 __pad1[3]; 19462306a36Sopenharmony_ci u32 intr; 19562306a36Sopenharmony_ci u32 intr_mask; 19662306a36Sopenharmony_ci u32 __pad2[2]; 19762306a36Sopenharmony_ci u32 start_ns; 19862306a36Sopenharmony_ci u32 start_sec; 19962306a36Sopenharmony_ci u32 pulse_ns; 20062306a36Sopenharmony_ci u32 pulse_sec; 20162306a36Sopenharmony_ci u32 period_ns; 20262306a36Sopenharmony_ci u32 period_sec; 20362306a36Sopenharmony_ci u32 repeat_count; 20462306a36Sopenharmony_ci}; 20562306a36Sopenharmony_ci 20662306a36Sopenharmony_cistruct frequency_reg { 20762306a36Sopenharmony_ci u32 ctrl; 20862306a36Sopenharmony_ci u32 status; 20962306a36Sopenharmony_ci}; 21062306a36Sopenharmony_ci 21162306a36Sopenharmony_cistruct board_config_reg { 21262306a36Sopenharmony_ci u32 mro50_serial_activate; 21362306a36Sopenharmony_ci}; 21462306a36Sopenharmony_ci 21562306a36Sopenharmony_ci#define FREQ_STATUS_VALID BIT(31) 21662306a36Sopenharmony_ci#define FREQ_STATUS_ERROR BIT(30) 21762306a36Sopenharmony_ci#define FREQ_STATUS_OVERRUN BIT(29) 21862306a36Sopenharmony_ci#define FREQ_STATUS_MASK GENMASK(23, 0) 21962306a36Sopenharmony_ci 22062306a36Sopenharmony_cistruct ptp_ocp_flash_info { 22162306a36Sopenharmony_ci const char *name; 22262306a36Sopenharmony_ci int pci_offset; 22362306a36Sopenharmony_ci int data_size; 22462306a36Sopenharmony_ci void *data; 22562306a36Sopenharmony_ci}; 22662306a36Sopenharmony_ci 22762306a36Sopenharmony_cistruct ptp_ocp_firmware_header { 22862306a36Sopenharmony_ci char magic[4]; 22962306a36Sopenharmony_ci __be16 pci_vendor_id; 23062306a36Sopenharmony_ci __be16 pci_device_id; 23162306a36Sopenharmony_ci __be32 image_size; 23262306a36Sopenharmony_ci __be16 hw_revision; 23362306a36Sopenharmony_ci __be16 crc; 23462306a36Sopenharmony_ci}; 23562306a36Sopenharmony_ci 23662306a36Sopenharmony_ci#define OCP_FIRMWARE_MAGIC_HEADER "OCPC" 23762306a36Sopenharmony_ci 23862306a36Sopenharmony_cistruct ptp_ocp_i2c_info { 23962306a36Sopenharmony_ci const char *name; 24062306a36Sopenharmony_ci unsigned long fixed_rate; 24162306a36Sopenharmony_ci size_t data_size; 24262306a36Sopenharmony_ci void *data; 24362306a36Sopenharmony_ci}; 24462306a36Sopenharmony_ci 24562306a36Sopenharmony_cistruct ptp_ocp_ext_info { 24662306a36Sopenharmony_ci int index; 24762306a36Sopenharmony_ci irqreturn_t (*irq_fcn)(int irq, void *priv); 24862306a36Sopenharmony_ci int (*enable)(void *priv, u32 req, bool enable); 24962306a36Sopenharmony_ci}; 25062306a36Sopenharmony_ci 25162306a36Sopenharmony_cistruct ptp_ocp_ext_src { 25262306a36Sopenharmony_ci void __iomem *mem; 25362306a36Sopenharmony_ci struct ptp_ocp *bp; 25462306a36Sopenharmony_ci struct ptp_ocp_ext_info *info; 25562306a36Sopenharmony_ci int irq_vec; 25662306a36Sopenharmony_ci}; 25762306a36Sopenharmony_ci 25862306a36Sopenharmony_cienum ptp_ocp_sma_mode { 25962306a36Sopenharmony_ci SMA_MODE_IN, 26062306a36Sopenharmony_ci SMA_MODE_OUT, 26162306a36Sopenharmony_ci}; 26262306a36Sopenharmony_ci 26362306a36Sopenharmony_cistruct ptp_ocp_sma_connector { 26462306a36Sopenharmony_ci enum ptp_ocp_sma_mode mode; 26562306a36Sopenharmony_ci bool fixed_fcn; 26662306a36Sopenharmony_ci bool fixed_dir; 26762306a36Sopenharmony_ci bool disabled; 26862306a36Sopenharmony_ci u8 default_fcn; 26962306a36Sopenharmony_ci}; 27062306a36Sopenharmony_ci 27162306a36Sopenharmony_cistruct ocp_attr_group { 27262306a36Sopenharmony_ci u64 cap; 27362306a36Sopenharmony_ci const struct attribute_group *group; 27462306a36Sopenharmony_ci}; 27562306a36Sopenharmony_ci 27662306a36Sopenharmony_ci#define OCP_CAP_BASIC BIT(0) 27762306a36Sopenharmony_ci#define OCP_CAP_SIGNAL BIT(1) 27862306a36Sopenharmony_ci#define OCP_CAP_FREQ BIT(2) 27962306a36Sopenharmony_ci 28062306a36Sopenharmony_cistruct ptp_ocp_signal { 28162306a36Sopenharmony_ci ktime_t period; 28262306a36Sopenharmony_ci ktime_t pulse; 28362306a36Sopenharmony_ci ktime_t phase; 28462306a36Sopenharmony_ci ktime_t start; 28562306a36Sopenharmony_ci int duty; 28662306a36Sopenharmony_ci bool polarity; 28762306a36Sopenharmony_ci bool running; 28862306a36Sopenharmony_ci}; 28962306a36Sopenharmony_ci 29062306a36Sopenharmony_cistruct ptp_ocp_serial_port { 29162306a36Sopenharmony_ci int line; 29262306a36Sopenharmony_ci int baud; 29362306a36Sopenharmony_ci}; 29462306a36Sopenharmony_ci 29562306a36Sopenharmony_ci#define OCP_BOARD_ID_LEN 13 29662306a36Sopenharmony_ci#define OCP_SERIAL_LEN 6 29762306a36Sopenharmony_ci 29862306a36Sopenharmony_cistruct ptp_ocp { 29962306a36Sopenharmony_ci struct pci_dev *pdev; 30062306a36Sopenharmony_ci struct device dev; 30162306a36Sopenharmony_ci spinlock_t lock; 30262306a36Sopenharmony_ci struct ocp_reg __iomem *reg; 30362306a36Sopenharmony_ci struct tod_reg __iomem *tod; 30462306a36Sopenharmony_ci struct pps_reg __iomem *pps_to_ext; 30562306a36Sopenharmony_ci struct pps_reg __iomem *pps_to_clk; 30662306a36Sopenharmony_ci struct board_config_reg __iomem *board_config; 30762306a36Sopenharmony_ci struct gpio_reg __iomem *pps_select; 30862306a36Sopenharmony_ci struct gpio_reg __iomem *sma_map1; 30962306a36Sopenharmony_ci struct gpio_reg __iomem *sma_map2; 31062306a36Sopenharmony_ci struct irig_master_reg __iomem *irig_out; 31162306a36Sopenharmony_ci struct irig_slave_reg __iomem *irig_in; 31262306a36Sopenharmony_ci struct dcf_master_reg __iomem *dcf_out; 31362306a36Sopenharmony_ci struct dcf_slave_reg __iomem *dcf_in; 31462306a36Sopenharmony_ci struct tod_reg __iomem *nmea_out; 31562306a36Sopenharmony_ci struct frequency_reg __iomem *freq_in[4]; 31662306a36Sopenharmony_ci struct ptp_ocp_ext_src *signal_out[4]; 31762306a36Sopenharmony_ci struct ptp_ocp_ext_src *pps; 31862306a36Sopenharmony_ci struct ptp_ocp_ext_src *ts0; 31962306a36Sopenharmony_ci struct ptp_ocp_ext_src *ts1; 32062306a36Sopenharmony_ci struct ptp_ocp_ext_src *ts2; 32162306a36Sopenharmony_ci struct ptp_ocp_ext_src *ts3; 32262306a36Sopenharmony_ci struct ptp_ocp_ext_src *ts4; 32362306a36Sopenharmony_ci struct ocp_art_gpio_reg __iomem *art_sma; 32462306a36Sopenharmony_ci struct img_reg __iomem *image; 32562306a36Sopenharmony_ci struct ptp_clock *ptp; 32662306a36Sopenharmony_ci struct ptp_clock_info ptp_info; 32762306a36Sopenharmony_ci struct platform_device *i2c_ctrl; 32862306a36Sopenharmony_ci struct platform_device *spi_flash; 32962306a36Sopenharmony_ci struct clk_hw *i2c_clk; 33062306a36Sopenharmony_ci struct timer_list watchdog; 33162306a36Sopenharmony_ci const struct attribute_group **attr_group; 33262306a36Sopenharmony_ci const struct ptp_ocp_eeprom_map *eeprom_map; 33362306a36Sopenharmony_ci struct dentry *debug_root; 33462306a36Sopenharmony_ci time64_t gnss_lost; 33562306a36Sopenharmony_ci int id; 33662306a36Sopenharmony_ci int n_irqs; 33762306a36Sopenharmony_ci struct ptp_ocp_serial_port gnss_port; 33862306a36Sopenharmony_ci struct ptp_ocp_serial_port gnss2_port; 33962306a36Sopenharmony_ci struct ptp_ocp_serial_port mac_port; /* miniature atomic clock */ 34062306a36Sopenharmony_ci struct ptp_ocp_serial_port nmea_port; 34162306a36Sopenharmony_ci bool fw_loader; 34262306a36Sopenharmony_ci u8 fw_tag; 34362306a36Sopenharmony_ci u16 fw_version; 34462306a36Sopenharmony_ci u8 board_id[OCP_BOARD_ID_LEN]; 34562306a36Sopenharmony_ci u8 serial[OCP_SERIAL_LEN]; 34662306a36Sopenharmony_ci bool has_eeprom_data; 34762306a36Sopenharmony_ci u32 pps_req_map; 34862306a36Sopenharmony_ci int flash_start; 34962306a36Sopenharmony_ci u32 utc_tai_offset; 35062306a36Sopenharmony_ci u32 ts_window_adjust; 35162306a36Sopenharmony_ci u64 fw_cap; 35262306a36Sopenharmony_ci struct ptp_ocp_signal signal[4]; 35362306a36Sopenharmony_ci struct ptp_ocp_sma_connector sma[4]; 35462306a36Sopenharmony_ci const struct ocp_sma_op *sma_op; 35562306a36Sopenharmony_ci}; 35662306a36Sopenharmony_ci 35762306a36Sopenharmony_ci#define OCP_REQ_TIMESTAMP BIT(0) 35862306a36Sopenharmony_ci#define OCP_REQ_PPS BIT(1) 35962306a36Sopenharmony_ci 36062306a36Sopenharmony_cistruct ocp_resource { 36162306a36Sopenharmony_ci unsigned long offset; 36262306a36Sopenharmony_ci int size; 36362306a36Sopenharmony_ci int irq_vec; 36462306a36Sopenharmony_ci int (*setup)(struct ptp_ocp *bp, struct ocp_resource *r); 36562306a36Sopenharmony_ci void *extra; 36662306a36Sopenharmony_ci unsigned long bp_offset; 36762306a36Sopenharmony_ci const char * const name; 36862306a36Sopenharmony_ci}; 36962306a36Sopenharmony_ci 37062306a36Sopenharmony_cistatic int ptp_ocp_register_mem(struct ptp_ocp *bp, struct ocp_resource *r); 37162306a36Sopenharmony_cistatic int ptp_ocp_register_i2c(struct ptp_ocp *bp, struct ocp_resource *r); 37262306a36Sopenharmony_cistatic int ptp_ocp_register_spi(struct ptp_ocp *bp, struct ocp_resource *r); 37362306a36Sopenharmony_cistatic int ptp_ocp_register_serial(struct ptp_ocp *bp, struct ocp_resource *r); 37462306a36Sopenharmony_cistatic int ptp_ocp_register_ext(struct ptp_ocp *bp, struct ocp_resource *r); 37562306a36Sopenharmony_cistatic int ptp_ocp_fb_board_init(struct ptp_ocp *bp, struct ocp_resource *r); 37662306a36Sopenharmony_cistatic irqreturn_t ptp_ocp_ts_irq(int irq, void *priv); 37762306a36Sopenharmony_cistatic irqreturn_t ptp_ocp_signal_irq(int irq, void *priv); 37862306a36Sopenharmony_cistatic int ptp_ocp_ts_enable(void *priv, u32 req, bool enable); 37962306a36Sopenharmony_cistatic int ptp_ocp_signal_from_perout(struct ptp_ocp *bp, int gen, 38062306a36Sopenharmony_ci struct ptp_perout_request *req); 38162306a36Sopenharmony_cistatic int ptp_ocp_signal_enable(void *priv, u32 req, bool enable); 38262306a36Sopenharmony_cistatic int ptp_ocp_sma_store(struct ptp_ocp *bp, const char *buf, int sma_nr); 38362306a36Sopenharmony_ci 38462306a36Sopenharmony_cistatic int ptp_ocp_art_board_init(struct ptp_ocp *bp, struct ocp_resource *r); 38562306a36Sopenharmony_ci 38662306a36Sopenharmony_cistatic const struct ocp_attr_group fb_timecard_groups[]; 38762306a36Sopenharmony_ci 38862306a36Sopenharmony_cistatic const struct ocp_attr_group art_timecard_groups[]; 38962306a36Sopenharmony_ci 39062306a36Sopenharmony_cistruct ptp_ocp_eeprom_map { 39162306a36Sopenharmony_ci u16 off; 39262306a36Sopenharmony_ci u16 len; 39362306a36Sopenharmony_ci u32 bp_offset; 39462306a36Sopenharmony_ci const void * const tag; 39562306a36Sopenharmony_ci}; 39662306a36Sopenharmony_ci 39762306a36Sopenharmony_ci#define EEPROM_ENTRY(addr, member) \ 39862306a36Sopenharmony_ci .off = addr, \ 39962306a36Sopenharmony_ci .len = sizeof_field(struct ptp_ocp, member), \ 40062306a36Sopenharmony_ci .bp_offset = offsetof(struct ptp_ocp, member) 40162306a36Sopenharmony_ci 40262306a36Sopenharmony_ci#define BP_MAP_ENTRY_ADDR(bp, map) ({ \ 40362306a36Sopenharmony_ci (void *)((uintptr_t)(bp) + (map)->bp_offset); \ 40462306a36Sopenharmony_ci}) 40562306a36Sopenharmony_ci 40662306a36Sopenharmony_cistatic struct ptp_ocp_eeprom_map fb_eeprom_map[] = { 40762306a36Sopenharmony_ci { EEPROM_ENTRY(0x43, board_id) }, 40862306a36Sopenharmony_ci { EEPROM_ENTRY(0x00, serial), .tag = "mac" }, 40962306a36Sopenharmony_ci { } 41062306a36Sopenharmony_ci}; 41162306a36Sopenharmony_ci 41262306a36Sopenharmony_cistatic struct ptp_ocp_eeprom_map art_eeprom_map[] = { 41362306a36Sopenharmony_ci { EEPROM_ENTRY(0x200 + 0x43, board_id) }, 41462306a36Sopenharmony_ci { EEPROM_ENTRY(0x200 + 0x63, serial) }, 41562306a36Sopenharmony_ci { } 41662306a36Sopenharmony_ci}; 41762306a36Sopenharmony_ci 41862306a36Sopenharmony_ci#define bp_assign_entry(bp, res, val) ({ \ 41962306a36Sopenharmony_ci uintptr_t addr = (uintptr_t)(bp) + (res)->bp_offset; \ 42062306a36Sopenharmony_ci *(typeof(val) *)addr = val; \ 42162306a36Sopenharmony_ci}) 42262306a36Sopenharmony_ci 42362306a36Sopenharmony_ci#define OCP_RES_LOCATION(member) \ 42462306a36Sopenharmony_ci .name = #member, .bp_offset = offsetof(struct ptp_ocp, member) 42562306a36Sopenharmony_ci 42662306a36Sopenharmony_ci#define OCP_MEM_RESOURCE(member) \ 42762306a36Sopenharmony_ci OCP_RES_LOCATION(member), .setup = ptp_ocp_register_mem 42862306a36Sopenharmony_ci 42962306a36Sopenharmony_ci#define OCP_SERIAL_RESOURCE(member) \ 43062306a36Sopenharmony_ci OCP_RES_LOCATION(member), .setup = ptp_ocp_register_serial 43162306a36Sopenharmony_ci 43262306a36Sopenharmony_ci#define OCP_I2C_RESOURCE(member) \ 43362306a36Sopenharmony_ci OCP_RES_LOCATION(member), .setup = ptp_ocp_register_i2c 43462306a36Sopenharmony_ci 43562306a36Sopenharmony_ci#define OCP_SPI_RESOURCE(member) \ 43662306a36Sopenharmony_ci OCP_RES_LOCATION(member), .setup = ptp_ocp_register_spi 43762306a36Sopenharmony_ci 43862306a36Sopenharmony_ci#define OCP_EXT_RESOURCE(member) \ 43962306a36Sopenharmony_ci OCP_RES_LOCATION(member), .setup = ptp_ocp_register_ext 44062306a36Sopenharmony_ci 44162306a36Sopenharmony_ci/* This is the MSI vector mapping used. 44262306a36Sopenharmony_ci * 0: PPS (TS5) 44362306a36Sopenharmony_ci * 1: TS0 44462306a36Sopenharmony_ci * 2: TS1 44562306a36Sopenharmony_ci * 3: GNSS1 44662306a36Sopenharmony_ci * 4: GNSS2 44762306a36Sopenharmony_ci * 5: MAC 44862306a36Sopenharmony_ci * 6: TS2 44962306a36Sopenharmony_ci * 7: I2C controller 45062306a36Sopenharmony_ci * 8: HWICAP (notused) 45162306a36Sopenharmony_ci * 9: SPI Flash 45262306a36Sopenharmony_ci * 10: NMEA 45362306a36Sopenharmony_ci * 11: Signal Generator 1 45462306a36Sopenharmony_ci * 12: Signal Generator 2 45562306a36Sopenharmony_ci * 13: Signal Generator 3 45662306a36Sopenharmony_ci * 14: Signal Generator 4 45762306a36Sopenharmony_ci * 15: TS3 45862306a36Sopenharmony_ci * 16: TS4 45962306a36Sopenharmony_ci -- 46062306a36Sopenharmony_ci * 8: Orolia TS1 46162306a36Sopenharmony_ci * 10: Orolia TS2 46262306a36Sopenharmony_ci * 11: Orolia TS0 (GNSS) 46362306a36Sopenharmony_ci * 12: Orolia PPS 46462306a36Sopenharmony_ci * 14: Orolia TS3 46562306a36Sopenharmony_ci * 15: Orolia TS4 46662306a36Sopenharmony_ci */ 46762306a36Sopenharmony_ci 46862306a36Sopenharmony_cistatic struct ocp_resource ocp_fb_resource[] = { 46962306a36Sopenharmony_ci { 47062306a36Sopenharmony_ci OCP_MEM_RESOURCE(reg), 47162306a36Sopenharmony_ci .offset = 0x01000000, .size = 0x10000, 47262306a36Sopenharmony_ci }, 47362306a36Sopenharmony_ci { 47462306a36Sopenharmony_ci OCP_EXT_RESOURCE(ts0), 47562306a36Sopenharmony_ci .offset = 0x01010000, .size = 0x10000, .irq_vec = 1, 47662306a36Sopenharmony_ci .extra = &(struct ptp_ocp_ext_info) { 47762306a36Sopenharmony_ci .index = 0, 47862306a36Sopenharmony_ci .irq_fcn = ptp_ocp_ts_irq, 47962306a36Sopenharmony_ci .enable = ptp_ocp_ts_enable, 48062306a36Sopenharmony_ci }, 48162306a36Sopenharmony_ci }, 48262306a36Sopenharmony_ci { 48362306a36Sopenharmony_ci OCP_EXT_RESOURCE(ts1), 48462306a36Sopenharmony_ci .offset = 0x01020000, .size = 0x10000, .irq_vec = 2, 48562306a36Sopenharmony_ci .extra = &(struct ptp_ocp_ext_info) { 48662306a36Sopenharmony_ci .index = 1, 48762306a36Sopenharmony_ci .irq_fcn = ptp_ocp_ts_irq, 48862306a36Sopenharmony_ci .enable = ptp_ocp_ts_enable, 48962306a36Sopenharmony_ci }, 49062306a36Sopenharmony_ci }, 49162306a36Sopenharmony_ci { 49262306a36Sopenharmony_ci OCP_EXT_RESOURCE(ts2), 49362306a36Sopenharmony_ci .offset = 0x01060000, .size = 0x10000, .irq_vec = 6, 49462306a36Sopenharmony_ci .extra = &(struct ptp_ocp_ext_info) { 49562306a36Sopenharmony_ci .index = 2, 49662306a36Sopenharmony_ci .irq_fcn = ptp_ocp_ts_irq, 49762306a36Sopenharmony_ci .enable = ptp_ocp_ts_enable, 49862306a36Sopenharmony_ci }, 49962306a36Sopenharmony_ci }, 50062306a36Sopenharmony_ci { 50162306a36Sopenharmony_ci OCP_EXT_RESOURCE(ts3), 50262306a36Sopenharmony_ci .offset = 0x01110000, .size = 0x10000, .irq_vec = 15, 50362306a36Sopenharmony_ci .extra = &(struct ptp_ocp_ext_info) { 50462306a36Sopenharmony_ci .index = 3, 50562306a36Sopenharmony_ci .irq_fcn = ptp_ocp_ts_irq, 50662306a36Sopenharmony_ci .enable = ptp_ocp_ts_enable, 50762306a36Sopenharmony_ci }, 50862306a36Sopenharmony_ci }, 50962306a36Sopenharmony_ci { 51062306a36Sopenharmony_ci OCP_EXT_RESOURCE(ts4), 51162306a36Sopenharmony_ci .offset = 0x01120000, .size = 0x10000, .irq_vec = 16, 51262306a36Sopenharmony_ci .extra = &(struct ptp_ocp_ext_info) { 51362306a36Sopenharmony_ci .index = 4, 51462306a36Sopenharmony_ci .irq_fcn = ptp_ocp_ts_irq, 51562306a36Sopenharmony_ci .enable = ptp_ocp_ts_enable, 51662306a36Sopenharmony_ci }, 51762306a36Sopenharmony_ci }, 51862306a36Sopenharmony_ci /* Timestamp for PHC and/or PPS generator */ 51962306a36Sopenharmony_ci { 52062306a36Sopenharmony_ci OCP_EXT_RESOURCE(pps), 52162306a36Sopenharmony_ci .offset = 0x010C0000, .size = 0x10000, .irq_vec = 0, 52262306a36Sopenharmony_ci .extra = &(struct ptp_ocp_ext_info) { 52362306a36Sopenharmony_ci .index = 5, 52462306a36Sopenharmony_ci .irq_fcn = ptp_ocp_ts_irq, 52562306a36Sopenharmony_ci .enable = ptp_ocp_ts_enable, 52662306a36Sopenharmony_ci }, 52762306a36Sopenharmony_ci }, 52862306a36Sopenharmony_ci { 52962306a36Sopenharmony_ci OCP_EXT_RESOURCE(signal_out[0]), 53062306a36Sopenharmony_ci .offset = 0x010D0000, .size = 0x10000, .irq_vec = 11, 53162306a36Sopenharmony_ci .extra = &(struct ptp_ocp_ext_info) { 53262306a36Sopenharmony_ci .index = 1, 53362306a36Sopenharmony_ci .irq_fcn = ptp_ocp_signal_irq, 53462306a36Sopenharmony_ci .enable = ptp_ocp_signal_enable, 53562306a36Sopenharmony_ci }, 53662306a36Sopenharmony_ci }, 53762306a36Sopenharmony_ci { 53862306a36Sopenharmony_ci OCP_EXT_RESOURCE(signal_out[1]), 53962306a36Sopenharmony_ci .offset = 0x010E0000, .size = 0x10000, .irq_vec = 12, 54062306a36Sopenharmony_ci .extra = &(struct ptp_ocp_ext_info) { 54162306a36Sopenharmony_ci .index = 2, 54262306a36Sopenharmony_ci .irq_fcn = ptp_ocp_signal_irq, 54362306a36Sopenharmony_ci .enable = ptp_ocp_signal_enable, 54462306a36Sopenharmony_ci }, 54562306a36Sopenharmony_ci }, 54662306a36Sopenharmony_ci { 54762306a36Sopenharmony_ci OCP_EXT_RESOURCE(signal_out[2]), 54862306a36Sopenharmony_ci .offset = 0x010F0000, .size = 0x10000, .irq_vec = 13, 54962306a36Sopenharmony_ci .extra = &(struct ptp_ocp_ext_info) { 55062306a36Sopenharmony_ci .index = 3, 55162306a36Sopenharmony_ci .irq_fcn = ptp_ocp_signal_irq, 55262306a36Sopenharmony_ci .enable = ptp_ocp_signal_enable, 55362306a36Sopenharmony_ci }, 55462306a36Sopenharmony_ci }, 55562306a36Sopenharmony_ci { 55662306a36Sopenharmony_ci OCP_EXT_RESOURCE(signal_out[3]), 55762306a36Sopenharmony_ci .offset = 0x01100000, .size = 0x10000, .irq_vec = 14, 55862306a36Sopenharmony_ci .extra = &(struct ptp_ocp_ext_info) { 55962306a36Sopenharmony_ci .index = 4, 56062306a36Sopenharmony_ci .irq_fcn = ptp_ocp_signal_irq, 56162306a36Sopenharmony_ci .enable = ptp_ocp_signal_enable, 56262306a36Sopenharmony_ci }, 56362306a36Sopenharmony_ci }, 56462306a36Sopenharmony_ci { 56562306a36Sopenharmony_ci OCP_MEM_RESOURCE(pps_to_ext), 56662306a36Sopenharmony_ci .offset = 0x01030000, .size = 0x10000, 56762306a36Sopenharmony_ci }, 56862306a36Sopenharmony_ci { 56962306a36Sopenharmony_ci OCP_MEM_RESOURCE(pps_to_clk), 57062306a36Sopenharmony_ci .offset = 0x01040000, .size = 0x10000, 57162306a36Sopenharmony_ci }, 57262306a36Sopenharmony_ci { 57362306a36Sopenharmony_ci OCP_MEM_RESOURCE(tod), 57462306a36Sopenharmony_ci .offset = 0x01050000, .size = 0x10000, 57562306a36Sopenharmony_ci }, 57662306a36Sopenharmony_ci { 57762306a36Sopenharmony_ci OCP_MEM_RESOURCE(irig_in), 57862306a36Sopenharmony_ci .offset = 0x01070000, .size = 0x10000, 57962306a36Sopenharmony_ci }, 58062306a36Sopenharmony_ci { 58162306a36Sopenharmony_ci OCP_MEM_RESOURCE(irig_out), 58262306a36Sopenharmony_ci .offset = 0x01080000, .size = 0x10000, 58362306a36Sopenharmony_ci }, 58462306a36Sopenharmony_ci { 58562306a36Sopenharmony_ci OCP_MEM_RESOURCE(dcf_in), 58662306a36Sopenharmony_ci .offset = 0x01090000, .size = 0x10000, 58762306a36Sopenharmony_ci }, 58862306a36Sopenharmony_ci { 58962306a36Sopenharmony_ci OCP_MEM_RESOURCE(dcf_out), 59062306a36Sopenharmony_ci .offset = 0x010A0000, .size = 0x10000, 59162306a36Sopenharmony_ci }, 59262306a36Sopenharmony_ci { 59362306a36Sopenharmony_ci OCP_MEM_RESOURCE(nmea_out), 59462306a36Sopenharmony_ci .offset = 0x010B0000, .size = 0x10000, 59562306a36Sopenharmony_ci }, 59662306a36Sopenharmony_ci { 59762306a36Sopenharmony_ci OCP_MEM_RESOURCE(image), 59862306a36Sopenharmony_ci .offset = 0x00020000, .size = 0x1000, 59962306a36Sopenharmony_ci }, 60062306a36Sopenharmony_ci { 60162306a36Sopenharmony_ci OCP_MEM_RESOURCE(pps_select), 60262306a36Sopenharmony_ci .offset = 0x00130000, .size = 0x1000, 60362306a36Sopenharmony_ci }, 60462306a36Sopenharmony_ci { 60562306a36Sopenharmony_ci OCP_MEM_RESOURCE(sma_map1), 60662306a36Sopenharmony_ci .offset = 0x00140000, .size = 0x1000, 60762306a36Sopenharmony_ci }, 60862306a36Sopenharmony_ci { 60962306a36Sopenharmony_ci OCP_MEM_RESOURCE(sma_map2), 61062306a36Sopenharmony_ci .offset = 0x00220000, .size = 0x1000, 61162306a36Sopenharmony_ci }, 61262306a36Sopenharmony_ci { 61362306a36Sopenharmony_ci OCP_I2C_RESOURCE(i2c_ctrl), 61462306a36Sopenharmony_ci .offset = 0x00150000, .size = 0x10000, .irq_vec = 7, 61562306a36Sopenharmony_ci .extra = &(struct ptp_ocp_i2c_info) { 61662306a36Sopenharmony_ci .name = "xiic-i2c", 61762306a36Sopenharmony_ci .fixed_rate = 50000000, 61862306a36Sopenharmony_ci .data_size = sizeof(struct xiic_i2c_platform_data), 61962306a36Sopenharmony_ci .data = &(struct xiic_i2c_platform_data) { 62062306a36Sopenharmony_ci .num_devices = 2, 62162306a36Sopenharmony_ci .devices = (struct i2c_board_info[]) { 62262306a36Sopenharmony_ci { I2C_BOARD_INFO("24c02", 0x50) }, 62362306a36Sopenharmony_ci { I2C_BOARD_INFO("24mac402", 0x58), 62462306a36Sopenharmony_ci .platform_data = "mac" }, 62562306a36Sopenharmony_ci }, 62662306a36Sopenharmony_ci }, 62762306a36Sopenharmony_ci }, 62862306a36Sopenharmony_ci }, 62962306a36Sopenharmony_ci { 63062306a36Sopenharmony_ci OCP_SERIAL_RESOURCE(gnss_port), 63162306a36Sopenharmony_ci .offset = 0x00160000 + 0x1000, .irq_vec = 3, 63262306a36Sopenharmony_ci .extra = &(struct ptp_ocp_serial_port) { 63362306a36Sopenharmony_ci .baud = 115200, 63462306a36Sopenharmony_ci }, 63562306a36Sopenharmony_ci }, 63662306a36Sopenharmony_ci { 63762306a36Sopenharmony_ci OCP_SERIAL_RESOURCE(gnss2_port), 63862306a36Sopenharmony_ci .offset = 0x00170000 + 0x1000, .irq_vec = 4, 63962306a36Sopenharmony_ci .extra = &(struct ptp_ocp_serial_port) { 64062306a36Sopenharmony_ci .baud = 115200, 64162306a36Sopenharmony_ci }, 64262306a36Sopenharmony_ci }, 64362306a36Sopenharmony_ci { 64462306a36Sopenharmony_ci OCP_SERIAL_RESOURCE(mac_port), 64562306a36Sopenharmony_ci .offset = 0x00180000 + 0x1000, .irq_vec = 5, 64662306a36Sopenharmony_ci .extra = &(struct ptp_ocp_serial_port) { 64762306a36Sopenharmony_ci .baud = 57600, 64862306a36Sopenharmony_ci }, 64962306a36Sopenharmony_ci }, 65062306a36Sopenharmony_ci { 65162306a36Sopenharmony_ci OCP_SERIAL_RESOURCE(nmea_port), 65262306a36Sopenharmony_ci .offset = 0x00190000 + 0x1000, .irq_vec = 10, 65362306a36Sopenharmony_ci }, 65462306a36Sopenharmony_ci { 65562306a36Sopenharmony_ci OCP_SPI_RESOURCE(spi_flash), 65662306a36Sopenharmony_ci .offset = 0x00310000, .size = 0x10000, .irq_vec = 9, 65762306a36Sopenharmony_ci .extra = &(struct ptp_ocp_flash_info) { 65862306a36Sopenharmony_ci .name = "xilinx_spi", .pci_offset = 0, 65962306a36Sopenharmony_ci .data_size = sizeof(struct xspi_platform_data), 66062306a36Sopenharmony_ci .data = &(struct xspi_platform_data) { 66162306a36Sopenharmony_ci .num_chipselect = 1, 66262306a36Sopenharmony_ci .bits_per_word = 8, 66362306a36Sopenharmony_ci .num_devices = 1, 66462306a36Sopenharmony_ci .force_irq = true, 66562306a36Sopenharmony_ci .devices = &(struct spi_board_info) { 66662306a36Sopenharmony_ci .modalias = "spi-nor", 66762306a36Sopenharmony_ci }, 66862306a36Sopenharmony_ci }, 66962306a36Sopenharmony_ci }, 67062306a36Sopenharmony_ci }, 67162306a36Sopenharmony_ci { 67262306a36Sopenharmony_ci OCP_MEM_RESOURCE(freq_in[0]), 67362306a36Sopenharmony_ci .offset = 0x01200000, .size = 0x10000, 67462306a36Sopenharmony_ci }, 67562306a36Sopenharmony_ci { 67662306a36Sopenharmony_ci OCP_MEM_RESOURCE(freq_in[1]), 67762306a36Sopenharmony_ci .offset = 0x01210000, .size = 0x10000, 67862306a36Sopenharmony_ci }, 67962306a36Sopenharmony_ci { 68062306a36Sopenharmony_ci OCP_MEM_RESOURCE(freq_in[2]), 68162306a36Sopenharmony_ci .offset = 0x01220000, .size = 0x10000, 68262306a36Sopenharmony_ci }, 68362306a36Sopenharmony_ci { 68462306a36Sopenharmony_ci OCP_MEM_RESOURCE(freq_in[3]), 68562306a36Sopenharmony_ci .offset = 0x01230000, .size = 0x10000, 68662306a36Sopenharmony_ci }, 68762306a36Sopenharmony_ci { 68862306a36Sopenharmony_ci .setup = ptp_ocp_fb_board_init, 68962306a36Sopenharmony_ci }, 69062306a36Sopenharmony_ci { } 69162306a36Sopenharmony_ci}; 69262306a36Sopenharmony_ci 69362306a36Sopenharmony_ci#define OCP_ART_CONFIG_SIZE 144 69462306a36Sopenharmony_ci#define OCP_ART_TEMP_TABLE_SIZE 368 69562306a36Sopenharmony_ci 69662306a36Sopenharmony_cistruct ocp_art_gpio_reg { 69762306a36Sopenharmony_ci struct { 69862306a36Sopenharmony_ci u32 gpio; 69962306a36Sopenharmony_ci u32 __pad[3]; 70062306a36Sopenharmony_ci } map[4]; 70162306a36Sopenharmony_ci}; 70262306a36Sopenharmony_ci 70362306a36Sopenharmony_cistatic struct ocp_resource ocp_art_resource[] = { 70462306a36Sopenharmony_ci { 70562306a36Sopenharmony_ci OCP_MEM_RESOURCE(reg), 70662306a36Sopenharmony_ci .offset = 0x01000000, .size = 0x10000, 70762306a36Sopenharmony_ci }, 70862306a36Sopenharmony_ci { 70962306a36Sopenharmony_ci OCP_SERIAL_RESOURCE(gnss_port), 71062306a36Sopenharmony_ci .offset = 0x00160000 + 0x1000, .irq_vec = 3, 71162306a36Sopenharmony_ci .extra = &(struct ptp_ocp_serial_port) { 71262306a36Sopenharmony_ci .baud = 115200, 71362306a36Sopenharmony_ci }, 71462306a36Sopenharmony_ci }, 71562306a36Sopenharmony_ci { 71662306a36Sopenharmony_ci OCP_MEM_RESOURCE(art_sma), 71762306a36Sopenharmony_ci .offset = 0x003C0000, .size = 0x1000, 71862306a36Sopenharmony_ci }, 71962306a36Sopenharmony_ci /* Timestamp associated with GNSS1 receiver PPS */ 72062306a36Sopenharmony_ci { 72162306a36Sopenharmony_ci OCP_EXT_RESOURCE(ts0), 72262306a36Sopenharmony_ci .offset = 0x360000, .size = 0x20, .irq_vec = 12, 72362306a36Sopenharmony_ci .extra = &(struct ptp_ocp_ext_info) { 72462306a36Sopenharmony_ci .index = 0, 72562306a36Sopenharmony_ci .irq_fcn = ptp_ocp_ts_irq, 72662306a36Sopenharmony_ci .enable = ptp_ocp_ts_enable, 72762306a36Sopenharmony_ci }, 72862306a36Sopenharmony_ci }, 72962306a36Sopenharmony_ci { 73062306a36Sopenharmony_ci OCP_EXT_RESOURCE(ts1), 73162306a36Sopenharmony_ci .offset = 0x380000, .size = 0x20, .irq_vec = 8, 73262306a36Sopenharmony_ci .extra = &(struct ptp_ocp_ext_info) { 73362306a36Sopenharmony_ci .index = 1, 73462306a36Sopenharmony_ci .irq_fcn = ptp_ocp_ts_irq, 73562306a36Sopenharmony_ci .enable = ptp_ocp_ts_enable, 73662306a36Sopenharmony_ci }, 73762306a36Sopenharmony_ci }, 73862306a36Sopenharmony_ci { 73962306a36Sopenharmony_ci OCP_EXT_RESOURCE(ts2), 74062306a36Sopenharmony_ci .offset = 0x390000, .size = 0x20, .irq_vec = 10, 74162306a36Sopenharmony_ci .extra = &(struct ptp_ocp_ext_info) { 74262306a36Sopenharmony_ci .index = 2, 74362306a36Sopenharmony_ci .irq_fcn = ptp_ocp_ts_irq, 74462306a36Sopenharmony_ci .enable = ptp_ocp_ts_enable, 74562306a36Sopenharmony_ci }, 74662306a36Sopenharmony_ci }, 74762306a36Sopenharmony_ci { 74862306a36Sopenharmony_ci OCP_EXT_RESOURCE(ts3), 74962306a36Sopenharmony_ci .offset = 0x3A0000, .size = 0x20, .irq_vec = 14, 75062306a36Sopenharmony_ci .extra = &(struct ptp_ocp_ext_info) { 75162306a36Sopenharmony_ci .index = 3, 75262306a36Sopenharmony_ci .irq_fcn = ptp_ocp_ts_irq, 75362306a36Sopenharmony_ci .enable = ptp_ocp_ts_enable, 75462306a36Sopenharmony_ci }, 75562306a36Sopenharmony_ci }, 75662306a36Sopenharmony_ci { 75762306a36Sopenharmony_ci OCP_EXT_RESOURCE(ts4), 75862306a36Sopenharmony_ci .offset = 0x3B0000, .size = 0x20, .irq_vec = 15, 75962306a36Sopenharmony_ci .extra = &(struct ptp_ocp_ext_info) { 76062306a36Sopenharmony_ci .index = 4, 76162306a36Sopenharmony_ci .irq_fcn = ptp_ocp_ts_irq, 76262306a36Sopenharmony_ci .enable = ptp_ocp_ts_enable, 76362306a36Sopenharmony_ci }, 76462306a36Sopenharmony_ci }, 76562306a36Sopenharmony_ci /* Timestamp associated with Internal PPS of the card */ 76662306a36Sopenharmony_ci { 76762306a36Sopenharmony_ci OCP_EXT_RESOURCE(pps), 76862306a36Sopenharmony_ci .offset = 0x00330000, .size = 0x20, .irq_vec = 11, 76962306a36Sopenharmony_ci .extra = &(struct ptp_ocp_ext_info) { 77062306a36Sopenharmony_ci .index = 5, 77162306a36Sopenharmony_ci .irq_fcn = ptp_ocp_ts_irq, 77262306a36Sopenharmony_ci .enable = ptp_ocp_ts_enable, 77362306a36Sopenharmony_ci }, 77462306a36Sopenharmony_ci }, 77562306a36Sopenharmony_ci { 77662306a36Sopenharmony_ci OCP_SPI_RESOURCE(spi_flash), 77762306a36Sopenharmony_ci .offset = 0x00310000, .size = 0x10000, .irq_vec = 9, 77862306a36Sopenharmony_ci .extra = &(struct ptp_ocp_flash_info) { 77962306a36Sopenharmony_ci .name = "spi_altera", .pci_offset = 0, 78062306a36Sopenharmony_ci .data_size = sizeof(struct altera_spi_platform_data), 78162306a36Sopenharmony_ci .data = &(struct altera_spi_platform_data) { 78262306a36Sopenharmony_ci .num_chipselect = 1, 78362306a36Sopenharmony_ci .num_devices = 1, 78462306a36Sopenharmony_ci .devices = &(struct spi_board_info) { 78562306a36Sopenharmony_ci .modalias = "spi-nor", 78662306a36Sopenharmony_ci }, 78762306a36Sopenharmony_ci }, 78862306a36Sopenharmony_ci }, 78962306a36Sopenharmony_ci }, 79062306a36Sopenharmony_ci { 79162306a36Sopenharmony_ci OCP_I2C_RESOURCE(i2c_ctrl), 79262306a36Sopenharmony_ci .offset = 0x350000, .size = 0x100, .irq_vec = 4, 79362306a36Sopenharmony_ci .extra = &(struct ptp_ocp_i2c_info) { 79462306a36Sopenharmony_ci .name = "ocores-i2c", 79562306a36Sopenharmony_ci .fixed_rate = 400000, 79662306a36Sopenharmony_ci .data_size = sizeof(struct ocores_i2c_platform_data), 79762306a36Sopenharmony_ci .data = &(struct ocores_i2c_platform_data) { 79862306a36Sopenharmony_ci .clock_khz = 125000, 79962306a36Sopenharmony_ci .bus_khz = 400, 80062306a36Sopenharmony_ci .num_devices = 1, 80162306a36Sopenharmony_ci .devices = &(struct i2c_board_info) { 80262306a36Sopenharmony_ci I2C_BOARD_INFO("24c08", 0x50), 80362306a36Sopenharmony_ci }, 80462306a36Sopenharmony_ci }, 80562306a36Sopenharmony_ci }, 80662306a36Sopenharmony_ci }, 80762306a36Sopenharmony_ci { 80862306a36Sopenharmony_ci OCP_SERIAL_RESOURCE(mac_port), 80962306a36Sopenharmony_ci .offset = 0x00190000, .irq_vec = 7, 81062306a36Sopenharmony_ci .extra = &(struct ptp_ocp_serial_port) { 81162306a36Sopenharmony_ci .baud = 9600, 81262306a36Sopenharmony_ci }, 81362306a36Sopenharmony_ci }, 81462306a36Sopenharmony_ci { 81562306a36Sopenharmony_ci OCP_MEM_RESOURCE(board_config), 81662306a36Sopenharmony_ci .offset = 0x210000, .size = 0x1000, 81762306a36Sopenharmony_ci }, 81862306a36Sopenharmony_ci { 81962306a36Sopenharmony_ci .setup = ptp_ocp_art_board_init, 82062306a36Sopenharmony_ci }, 82162306a36Sopenharmony_ci { } 82262306a36Sopenharmony_ci}; 82362306a36Sopenharmony_ci 82462306a36Sopenharmony_cistatic const struct pci_device_id ptp_ocp_pcidev_id[] = { 82562306a36Sopenharmony_ci { PCI_DEVICE_DATA(FACEBOOK, TIMECARD, &ocp_fb_resource) }, 82662306a36Sopenharmony_ci { PCI_DEVICE_DATA(CELESTICA, TIMECARD, &ocp_fb_resource) }, 82762306a36Sopenharmony_ci { PCI_DEVICE_DATA(OROLIA, ARTCARD, &ocp_art_resource) }, 82862306a36Sopenharmony_ci { } 82962306a36Sopenharmony_ci}; 83062306a36Sopenharmony_ciMODULE_DEVICE_TABLE(pci, ptp_ocp_pcidev_id); 83162306a36Sopenharmony_ci 83262306a36Sopenharmony_cistatic DEFINE_MUTEX(ptp_ocp_lock); 83362306a36Sopenharmony_cistatic DEFINE_IDR(ptp_ocp_idr); 83462306a36Sopenharmony_ci 83562306a36Sopenharmony_cistruct ocp_selector { 83662306a36Sopenharmony_ci const char *name; 83762306a36Sopenharmony_ci int value; 83862306a36Sopenharmony_ci}; 83962306a36Sopenharmony_ci 84062306a36Sopenharmony_cistatic const struct ocp_selector ptp_ocp_clock[] = { 84162306a36Sopenharmony_ci { .name = "NONE", .value = 0 }, 84262306a36Sopenharmony_ci { .name = "TOD", .value = 1 }, 84362306a36Sopenharmony_ci { .name = "IRIG", .value = 2 }, 84462306a36Sopenharmony_ci { .name = "PPS", .value = 3 }, 84562306a36Sopenharmony_ci { .name = "PTP", .value = 4 }, 84662306a36Sopenharmony_ci { .name = "RTC", .value = 5 }, 84762306a36Sopenharmony_ci { .name = "DCF", .value = 6 }, 84862306a36Sopenharmony_ci { .name = "REGS", .value = 0xfe }, 84962306a36Sopenharmony_ci { .name = "EXT", .value = 0xff }, 85062306a36Sopenharmony_ci { } 85162306a36Sopenharmony_ci}; 85262306a36Sopenharmony_ci 85362306a36Sopenharmony_ci#define SMA_DISABLE BIT(16) 85462306a36Sopenharmony_ci#define SMA_ENABLE BIT(15) 85562306a36Sopenharmony_ci#define SMA_SELECT_MASK GENMASK(14, 0) 85662306a36Sopenharmony_ci 85762306a36Sopenharmony_cistatic const struct ocp_selector ptp_ocp_sma_in[] = { 85862306a36Sopenharmony_ci { .name = "10Mhz", .value = 0x0000 }, 85962306a36Sopenharmony_ci { .name = "PPS1", .value = 0x0001 }, 86062306a36Sopenharmony_ci { .name = "PPS2", .value = 0x0002 }, 86162306a36Sopenharmony_ci { .name = "TS1", .value = 0x0004 }, 86262306a36Sopenharmony_ci { .name = "TS2", .value = 0x0008 }, 86362306a36Sopenharmony_ci { .name = "IRIG", .value = 0x0010 }, 86462306a36Sopenharmony_ci { .name = "DCF", .value = 0x0020 }, 86562306a36Sopenharmony_ci { .name = "TS3", .value = 0x0040 }, 86662306a36Sopenharmony_ci { .name = "TS4", .value = 0x0080 }, 86762306a36Sopenharmony_ci { .name = "FREQ1", .value = 0x0100 }, 86862306a36Sopenharmony_ci { .name = "FREQ2", .value = 0x0200 }, 86962306a36Sopenharmony_ci { .name = "FREQ3", .value = 0x0400 }, 87062306a36Sopenharmony_ci { .name = "FREQ4", .value = 0x0800 }, 87162306a36Sopenharmony_ci { .name = "None", .value = SMA_DISABLE }, 87262306a36Sopenharmony_ci { } 87362306a36Sopenharmony_ci}; 87462306a36Sopenharmony_ci 87562306a36Sopenharmony_cistatic const struct ocp_selector ptp_ocp_sma_out[] = { 87662306a36Sopenharmony_ci { .name = "10Mhz", .value = 0x0000 }, 87762306a36Sopenharmony_ci { .name = "PHC", .value = 0x0001 }, 87862306a36Sopenharmony_ci { .name = "MAC", .value = 0x0002 }, 87962306a36Sopenharmony_ci { .name = "GNSS1", .value = 0x0004 }, 88062306a36Sopenharmony_ci { .name = "GNSS2", .value = 0x0008 }, 88162306a36Sopenharmony_ci { .name = "IRIG", .value = 0x0010 }, 88262306a36Sopenharmony_ci { .name = "DCF", .value = 0x0020 }, 88362306a36Sopenharmony_ci { .name = "GEN1", .value = 0x0040 }, 88462306a36Sopenharmony_ci { .name = "GEN2", .value = 0x0080 }, 88562306a36Sopenharmony_ci { .name = "GEN3", .value = 0x0100 }, 88662306a36Sopenharmony_ci { .name = "GEN4", .value = 0x0200 }, 88762306a36Sopenharmony_ci { .name = "GND", .value = 0x2000 }, 88862306a36Sopenharmony_ci { .name = "VCC", .value = 0x4000 }, 88962306a36Sopenharmony_ci { } 89062306a36Sopenharmony_ci}; 89162306a36Sopenharmony_ci 89262306a36Sopenharmony_cistatic const struct ocp_selector ptp_ocp_art_sma_in[] = { 89362306a36Sopenharmony_ci { .name = "PPS1", .value = 0x0001 }, 89462306a36Sopenharmony_ci { .name = "10Mhz", .value = 0x0008 }, 89562306a36Sopenharmony_ci { } 89662306a36Sopenharmony_ci}; 89762306a36Sopenharmony_ci 89862306a36Sopenharmony_cistatic const struct ocp_selector ptp_ocp_art_sma_out[] = { 89962306a36Sopenharmony_ci { .name = "PHC", .value = 0x0002 }, 90062306a36Sopenharmony_ci { .name = "GNSS", .value = 0x0004 }, 90162306a36Sopenharmony_ci { .name = "10Mhz", .value = 0x0010 }, 90262306a36Sopenharmony_ci { } 90362306a36Sopenharmony_ci}; 90462306a36Sopenharmony_ci 90562306a36Sopenharmony_cistruct ocp_sma_op { 90662306a36Sopenharmony_ci const struct ocp_selector *tbl[2]; 90762306a36Sopenharmony_ci void (*init)(struct ptp_ocp *bp); 90862306a36Sopenharmony_ci u32 (*get)(struct ptp_ocp *bp, int sma_nr); 90962306a36Sopenharmony_ci int (*set_inputs)(struct ptp_ocp *bp, int sma_nr, u32 val); 91062306a36Sopenharmony_ci int (*set_output)(struct ptp_ocp *bp, int sma_nr, u32 val); 91162306a36Sopenharmony_ci}; 91262306a36Sopenharmony_ci 91362306a36Sopenharmony_cistatic void 91462306a36Sopenharmony_ciptp_ocp_sma_init(struct ptp_ocp *bp) 91562306a36Sopenharmony_ci{ 91662306a36Sopenharmony_ci return bp->sma_op->init(bp); 91762306a36Sopenharmony_ci} 91862306a36Sopenharmony_ci 91962306a36Sopenharmony_cistatic u32 92062306a36Sopenharmony_ciptp_ocp_sma_get(struct ptp_ocp *bp, int sma_nr) 92162306a36Sopenharmony_ci{ 92262306a36Sopenharmony_ci return bp->sma_op->get(bp, sma_nr); 92362306a36Sopenharmony_ci} 92462306a36Sopenharmony_ci 92562306a36Sopenharmony_cistatic int 92662306a36Sopenharmony_ciptp_ocp_sma_set_inputs(struct ptp_ocp *bp, int sma_nr, u32 val) 92762306a36Sopenharmony_ci{ 92862306a36Sopenharmony_ci return bp->sma_op->set_inputs(bp, sma_nr, val); 92962306a36Sopenharmony_ci} 93062306a36Sopenharmony_ci 93162306a36Sopenharmony_cistatic int 93262306a36Sopenharmony_ciptp_ocp_sma_set_output(struct ptp_ocp *bp, int sma_nr, u32 val) 93362306a36Sopenharmony_ci{ 93462306a36Sopenharmony_ci return bp->sma_op->set_output(bp, sma_nr, val); 93562306a36Sopenharmony_ci} 93662306a36Sopenharmony_ci 93762306a36Sopenharmony_cistatic const char * 93862306a36Sopenharmony_ciptp_ocp_select_name_from_val(const struct ocp_selector *tbl, int val) 93962306a36Sopenharmony_ci{ 94062306a36Sopenharmony_ci int i; 94162306a36Sopenharmony_ci 94262306a36Sopenharmony_ci for (i = 0; tbl[i].name; i++) 94362306a36Sopenharmony_ci if (tbl[i].value == val) 94462306a36Sopenharmony_ci return tbl[i].name; 94562306a36Sopenharmony_ci return NULL; 94662306a36Sopenharmony_ci} 94762306a36Sopenharmony_ci 94862306a36Sopenharmony_cistatic int 94962306a36Sopenharmony_ciptp_ocp_select_val_from_name(const struct ocp_selector *tbl, const char *name) 95062306a36Sopenharmony_ci{ 95162306a36Sopenharmony_ci const char *select; 95262306a36Sopenharmony_ci int i; 95362306a36Sopenharmony_ci 95462306a36Sopenharmony_ci for (i = 0; tbl[i].name; i++) { 95562306a36Sopenharmony_ci select = tbl[i].name; 95662306a36Sopenharmony_ci if (!strncasecmp(name, select, strlen(select))) 95762306a36Sopenharmony_ci return tbl[i].value; 95862306a36Sopenharmony_ci } 95962306a36Sopenharmony_ci return -EINVAL; 96062306a36Sopenharmony_ci} 96162306a36Sopenharmony_ci 96262306a36Sopenharmony_cistatic ssize_t 96362306a36Sopenharmony_ciptp_ocp_select_table_show(const struct ocp_selector *tbl, char *buf) 96462306a36Sopenharmony_ci{ 96562306a36Sopenharmony_ci ssize_t count; 96662306a36Sopenharmony_ci int i; 96762306a36Sopenharmony_ci 96862306a36Sopenharmony_ci count = 0; 96962306a36Sopenharmony_ci for (i = 0; tbl[i].name; i++) 97062306a36Sopenharmony_ci count += sysfs_emit_at(buf, count, "%s ", tbl[i].name); 97162306a36Sopenharmony_ci if (count) 97262306a36Sopenharmony_ci count--; 97362306a36Sopenharmony_ci count += sysfs_emit_at(buf, count, "\n"); 97462306a36Sopenharmony_ci return count; 97562306a36Sopenharmony_ci} 97662306a36Sopenharmony_ci 97762306a36Sopenharmony_cistatic int 97862306a36Sopenharmony_ci__ptp_ocp_gettime_locked(struct ptp_ocp *bp, struct timespec64 *ts, 97962306a36Sopenharmony_ci struct ptp_system_timestamp *sts) 98062306a36Sopenharmony_ci{ 98162306a36Sopenharmony_ci u32 ctrl, time_sec, time_ns; 98262306a36Sopenharmony_ci int i; 98362306a36Sopenharmony_ci 98462306a36Sopenharmony_ci ptp_read_system_prets(sts); 98562306a36Sopenharmony_ci 98662306a36Sopenharmony_ci ctrl = OCP_CTRL_READ_TIME_REQ | OCP_CTRL_ENABLE; 98762306a36Sopenharmony_ci iowrite32(ctrl, &bp->reg->ctrl); 98862306a36Sopenharmony_ci 98962306a36Sopenharmony_ci for (i = 0; i < 100; i++) { 99062306a36Sopenharmony_ci ctrl = ioread32(&bp->reg->ctrl); 99162306a36Sopenharmony_ci if (ctrl & OCP_CTRL_READ_TIME_DONE) 99262306a36Sopenharmony_ci break; 99362306a36Sopenharmony_ci } 99462306a36Sopenharmony_ci ptp_read_system_postts(sts); 99562306a36Sopenharmony_ci 99662306a36Sopenharmony_ci if (sts && bp->ts_window_adjust) { 99762306a36Sopenharmony_ci s64 ns = timespec64_to_ns(&sts->post_ts); 99862306a36Sopenharmony_ci 99962306a36Sopenharmony_ci sts->post_ts = ns_to_timespec64(ns - bp->ts_window_adjust); 100062306a36Sopenharmony_ci } 100162306a36Sopenharmony_ci 100262306a36Sopenharmony_ci time_ns = ioread32(&bp->reg->time_ns); 100362306a36Sopenharmony_ci time_sec = ioread32(&bp->reg->time_sec); 100462306a36Sopenharmony_ci 100562306a36Sopenharmony_ci ts->tv_sec = time_sec; 100662306a36Sopenharmony_ci ts->tv_nsec = time_ns; 100762306a36Sopenharmony_ci 100862306a36Sopenharmony_ci return ctrl & OCP_CTRL_READ_TIME_DONE ? 0 : -ETIMEDOUT; 100962306a36Sopenharmony_ci} 101062306a36Sopenharmony_ci 101162306a36Sopenharmony_cistatic int 101262306a36Sopenharmony_ciptp_ocp_gettimex(struct ptp_clock_info *ptp_info, struct timespec64 *ts, 101362306a36Sopenharmony_ci struct ptp_system_timestamp *sts) 101462306a36Sopenharmony_ci{ 101562306a36Sopenharmony_ci struct ptp_ocp *bp = container_of(ptp_info, struct ptp_ocp, ptp_info); 101662306a36Sopenharmony_ci unsigned long flags; 101762306a36Sopenharmony_ci int err; 101862306a36Sopenharmony_ci 101962306a36Sopenharmony_ci spin_lock_irqsave(&bp->lock, flags); 102062306a36Sopenharmony_ci err = __ptp_ocp_gettime_locked(bp, ts, sts); 102162306a36Sopenharmony_ci spin_unlock_irqrestore(&bp->lock, flags); 102262306a36Sopenharmony_ci 102362306a36Sopenharmony_ci return err; 102462306a36Sopenharmony_ci} 102562306a36Sopenharmony_ci 102662306a36Sopenharmony_cistatic void 102762306a36Sopenharmony_ci__ptp_ocp_settime_locked(struct ptp_ocp *bp, const struct timespec64 *ts) 102862306a36Sopenharmony_ci{ 102962306a36Sopenharmony_ci u32 ctrl, time_sec, time_ns; 103062306a36Sopenharmony_ci u32 select; 103162306a36Sopenharmony_ci 103262306a36Sopenharmony_ci time_ns = ts->tv_nsec; 103362306a36Sopenharmony_ci time_sec = ts->tv_sec; 103462306a36Sopenharmony_ci 103562306a36Sopenharmony_ci select = ioread32(&bp->reg->select); 103662306a36Sopenharmony_ci iowrite32(OCP_SELECT_CLK_REG, &bp->reg->select); 103762306a36Sopenharmony_ci 103862306a36Sopenharmony_ci iowrite32(time_ns, &bp->reg->adjust_ns); 103962306a36Sopenharmony_ci iowrite32(time_sec, &bp->reg->adjust_sec); 104062306a36Sopenharmony_ci 104162306a36Sopenharmony_ci ctrl = OCP_CTRL_ADJUST_TIME | OCP_CTRL_ENABLE; 104262306a36Sopenharmony_ci iowrite32(ctrl, &bp->reg->ctrl); 104362306a36Sopenharmony_ci 104462306a36Sopenharmony_ci /* restore clock selection */ 104562306a36Sopenharmony_ci iowrite32(select >> 16, &bp->reg->select); 104662306a36Sopenharmony_ci} 104762306a36Sopenharmony_ci 104862306a36Sopenharmony_cistatic int 104962306a36Sopenharmony_ciptp_ocp_settime(struct ptp_clock_info *ptp_info, const struct timespec64 *ts) 105062306a36Sopenharmony_ci{ 105162306a36Sopenharmony_ci struct ptp_ocp *bp = container_of(ptp_info, struct ptp_ocp, ptp_info); 105262306a36Sopenharmony_ci unsigned long flags; 105362306a36Sopenharmony_ci 105462306a36Sopenharmony_ci spin_lock_irqsave(&bp->lock, flags); 105562306a36Sopenharmony_ci __ptp_ocp_settime_locked(bp, ts); 105662306a36Sopenharmony_ci spin_unlock_irqrestore(&bp->lock, flags); 105762306a36Sopenharmony_ci 105862306a36Sopenharmony_ci return 0; 105962306a36Sopenharmony_ci} 106062306a36Sopenharmony_ci 106162306a36Sopenharmony_cistatic void 106262306a36Sopenharmony_ci__ptp_ocp_adjtime_locked(struct ptp_ocp *bp, u32 adj_val) 106362306a36Sopenharmony_ci{ 106462306a36Sopenharmony_ci u32 select, ctrl; 106562306a36Sopenharmony_ci 106662306a36Sopenharmony_ci select = ioread32(&bp->reg->select); 106762306a36Sopenharmony_ci iowrite32(OCP_SELECT_CLK_REG, &bp->reg->select); 106862306a36Sopenharmony_ci 106962306a36Sopenharmony_ci iowrite32(adj_val, &bp->reg->offset_ns); 107062306a36Sopenharmony_ci iowrite32(NSEC_PER_SEC, &bp->reg->offset_window_ns); 107162306a36Sopenharmony_ci 107262306a36Sopenharmony_ci ctrl = OCP_CTRL_ADJUST_OFFSET | OCP_CTRL_ENABLE; 107362306a36Sopenharmony_ci iowrite32(ctrl, &bp->reg->ctrl); 107462306a36Sopenharmony_ci 107562306a36Sopenharmony_ci /* restore clock selection */ 107662306a36Sopenharmony_ci iowrite32(select >> 16, &bp->reg->select); 107762306a36Sopenharmony_ci} 107862306a36Sopenharmony_ci 107962306a36Sopenharmony_cistatic void 108062306a36Sopenharmony_ciptp_ocp_adjtime_coarse(struct ptp_ocp *bp, s64 delta_ns) 108162306a36Sopenharmony_ci{ 108262306a36Sopenharmony_ci struct timespec64 ts; 108362306a36Sopenharmony_ci unsigned long flags; 108462306a36Sopenharmony_ci int err; 108562306a36Sopenharmony_ci 108662306a36Sopenharmony_ci spin_lock_irqsave(&bp->lock, flags); 108762306a36Sopenharmony_ci err = __ptp_ocp_gettime_locked(bp, &ts, NULL); 108862306a36Sopenharmony_ci if (likely(!err)) { 108962306a36Sopenharmony_ci set_normalized_timespec64(&ts, ts.tv_sec, 109062306a36Sopenharmony_ci ts.tv_nsec + delta_ns); 109162306a36Sopenharmony_ci __ptp_ocp_settime_locked(bp, &ts); 109262306a36Sopenharmony_ci } 109362306a36Sopenharmony_ci spin_unlock_irqrestore(&bp->lock, flags); 109462306a36Sopenharmony_ci} 109562306a36Sopenharmony_ci 109662306a36Sopenharmony_cistatic int 109762306a36Sopenharmony_ciptp_ocp_adjtime(struct ptp_clock_info *ptp_info, s64 delta_ns) 109862306a36Sopenharmony_ci{ 109962306a36Sopenharmony_ci struct ptp_ocp *bp = container_of(ptp_info, struct ptp_ocp, ptp_info); 110062306a36Sopenharmony_ci unsigned long flags; 110162306a36Sopenharmony_ci u32 adj_ns, sign; 110262306a36Sopenharmony_ci 110362306a36Sopenharmony_ci if (delta_ns > NSEC_PER_SEC || -delta_ns > NSEC_PER_SEC) { 110462306a36Sopenharmony_ci ptp_ocp_adjtime_coarse(bp, delta_ns); 110562306a36Sopenharmony_ci return 0; 110662306a36Sopenharmony_ci } 110762306a36Sopenharmony_ci 110862306a36Sopenharmony_ci sign = delta_ns < 0 ? BIT(31) : 0; 110962306a36Sopenharmony_ci adj_ns = sign ? -delta_ns : delta_ns; 111062306a36Sopenharmony_ci 111162306a36Sopenharmony_ci spin_lock_irqsave(&bp->lock, flags); 111262306a36Sopenharmony_ci __ptp_ocp_adjtime_locked(bp, sign | adj_ns); 111362306a36Sopenharmony_ci spin_unlock_irqrestore(&bp->lock, flags); 111462306a36Sopenharmony_ci 111562306a36Sopenharmony_ci return 0; 111662306a36Sopenharmony_ci} 111762306a36Sopenharmony_ci 111862306a36Sopenharmony_cistatic int 111962306a36Sopenharmony_ciptp_ocp_null_adjfine(struct ptp_clock_info *ptp_info, long scaled_ppm) 112062306a36Sopenharmony_ci{ 112162306a36Sopenharmony_ci if (scaled_ppm == 0) 112262306a36Sopenharmony_ci return 0; 112362306a36Sopenharmony_ci 112462306a36Sopenharmony_ci return -EOPNOTSUPP; 112562306a36Sopenharmony_ci} 112662306a36Sopenharmony_ci 112762306a36Sopenharmony_cistatic s32 112862306a36Sopenharmony_ciptp_ocp_null_getmaxphase(struct ptp_clock_info *ptp_info) 112962306a36Sopenharmony_ci{ 113062306a36Sopenharmony_ci return 0; 113162306a36Sopenharmony_ci} 113262306a36Sopenharmony_ci 113362306a36Sopenharmony_cistatic int 113462306a36Sopenharmony_ciptp_ocp_null_adjphase(struct ptp_clock_info *ptp_info, s32 phase_ns) 113562306a36Sopenharmony_ci{ 113662306a36Sopenharmony_ci return -EOPNOTSUPP; 113762306a36Sopenharmony_ci} 113862306a36Sopenharmony_ci 113962306a36Sopenharmony_cistatic int 114062306a36Sopenharmony_ciptp_ocp_enable(struct ptp_clock_info *ptp_info, struct ptp_clock_request *rq, 114162306a36Sopenharmony_ci int on) 114262306a36Sopenharmony_ci{ 114362306a36Sopenharmony_ci struct ptp_ocp *bp = container_of(ptp_info, struct ptp_ocp, ptp_info); 114462306a36Sopenharmony_ci struct ptp_ocp_ext_src *ext = NULL; 114562306a36Sopenharmony_ci u32 req; 114662306a36Sopenharmony_ci int err; 114762306a36Sopenharmony_ci 114862306a36Sopenharmony_ci switch (rq->type) { 114962306a36Sopenharmony_ci case PTP_CLK_REQ_EXTTS: 115062306a36Sopenharmony_ci req = OCP_REQ_TIMESTAMP; 115162306a36Sopenharmony_ci switch (rq->extts.index) { 115262306a36Sopenharmony_ci case 0: 115362306a36Sopenharmony_ci ext = bp->ts0; 115462306a36Sopenharmony_ci break; 115562306a36Sopenharmony_ci case 1: 115662306a36Sopenharmony_ci ext = bp->ts1; 115762306a36Sopenharmony_ci break; 115862306a36Sopenharmony_ci case 2: 115962306a36Sopenharmony_ci ext = bp->ts2; 116062306a36Sopenharmony_ci break; 116162306a36Sopenharmony_ci case 3: 116262306a36Sopenharmony_ci ext = bp->ts3; 116362306a36Sopenharmony_ci break; 116462306a36Sopenharmony_ci case 4: 116562306a36Sopenharmony_ci ext = bp->ts4; 116662306a36Sopenharmony_ci break; 116762306a36Sopenharmony_ci case 5: 116862306a36Sopenharmony_ci ext = bp->pps; 116962306a36Sopenharmony_ci break; 117062306a36Sopenharmony_ci } 117162306a36Sopenharmony_ci break; 117262306a36Sopenharmony_ci case PTP_CLK_REQ_PPS: 117362306a36Sopenharmony_ci req = OCP_REQ_PPS; 117462306a36Sopenharmony_ci ext = bp->pps; 117562306a36Sopenharmony_ci break; 117662306a36Sopenharmony_ci case PTP_CLK_REQ_PEROUT: 117762306a36Sopenharmony_ci switch (rq->perout.index) { 117862306a36Sopenharmony_ci case 0: 117962306a36Sopenharmony_ci /* This is a request for 1PPS on an output SMA. 118062306a36Sopenharmony_ci * Allow, but assume manual configuration. 118162306a36Sopenharmony_ci */ 118262306a36Sopenharmony_ci if (on && (rq->perout.period.sec != 1 || 118362306a36Sopenharmony_ci rq->perout.period.nsec != 0)) 118462306a36Sopenharmony_ci return -EINVAL; 118562306a36Sopenharmony_ci return 0; 118662306a36Sopenharmony_ci case 1: 118762306a36Sopenharmony_ci case 2: 118862306a36Sopenharmony_ci case 3: 118962306a36Sopenharmony_ci case 4: 119062306a36Sopenharmony_ci req = rq->perout.index - 1; 119162306a36Sopenharmony_ci ext = bp->signal_out[req]; 119262306a36Sopenharmony_ci err = ptp_ocp_signal_from_perout(bp, req, &rq->perout); 119362306a36Sopenharmony_ci if (err) 119462306a36Sopenharmony_ci return err; 119562306a36Sopenharmony_ci break; 119662306a36Sopenharmony_ci } 119762306a36Sopenharmony_ci break; 119862306a36Sopenharmony_ci default: 119962306a36Sopenharmony_ci return -EOPNOTSUPP; 120062306a36Sopenharmony_ci } 120162306a36Sopenharmony_ci 120262306a36Sopenharmony_ci err = -ENXIO; 120362306a36Sopenharmony_ci if (ext) 120462306a36Sopenharmony_ci err = ext->info->enable(ext, req, on); 120562306a36Sopenharmony_ci 120662306a36Sopenharmony_ci return err; 120762306a36Sopenharmony_ci} 120862306a36Sopenharmony_ci 120962306a36Sopenharmony_cistatic int 121062306a36Sopenharmony_ciptp_ocp_verify(struct ptp_clock_info *ptp_info, unsigned pin, 121162306a36Sopenharmony_ci enum ptp_pin_function func, unsigned chan) 121262306a36Sopenharmony_ci{ 121362306a36Sopenharmony_ci struct ptp_ocp *bp = container_of(ptp_info, struct ptp_ocp, ptp_info); 121462306a36Sopenharmony_ci char buf[16]; 121562306a36Sopenharmony_ci 121662306a36Sopenharmony_ci switch (func) { 121762306a36Sopenharmony_ci case PTP_PF_NONE: 121862306a36Sopenharmony_ci snprintf(buf, sizeof(buf), "IN: None"); 121962306a36Sopenharmony_ci break; 122062306a36Sopenharmony_ci case PTP_PF_EXTTS: 122162306a36Sopenharmony_ci /* Allow timestamps, but require sysfs configuration. */ 122262306a36Sopenharmony_ci return 0; 122362306a36Sopenharmony_ci case PTP_PF_PEROUT: 122462306a36Sopenharmony_ci /* channel 0 is 1PPS from PHC. 122562306a36Sopenharmony_ci * channels 1..4 are the frequency generators. 122662306a36Sopenharmony_ci */ 122762306a36Sopenharmony_ci if (chan) 122862306a36Sopenharmony_ci snprintf(buf, sizeof(buf), "OUT: GEN%d", chan); 122962306a36Sopenharmony_ci else 123062306a36Sopenharmony_ci snprintf(buf, sizeof(buf), "OUT: PHC"); 123162306a36Sopenharmony_ci break; 123262306a36Sopenharmony_ci default: 123362306a36Sopenharmony_ci return -EOPNOTSUPP; 123462306a36Sopenharmony_ci } 123562306a36Sopenharmony_ci 123662306a36Sopenharmony_ci return ptp_ocp_sma_store(bp, buf, pin + 1); 123762306a36Sopenharmony_ci} 123862306a36Sopenharmony_ci 123962306a36Sopenharmony_cistatic const struct ptp_clock_info ptp_ocp_clock_info = { 124062306a36Sopenharmony_ci .owner = THIS_MODULE, 124162306a36Sopenharmony_ci .name = KBUILD_MODNAME, 124262306a36Sopenharmony_ci .max_adj = 100000000, 124362306a36Sopenharmony_ci .gettimex64 = ptp_ocp_gettimex, 124462306a36Sopenharmony_ci .settime64 = ptp_ocp_settime, 124562306a36Sopenharmony_ci .adjtime = ptp_ocp_adjtime, 124662306a36Sopenharmony_ci .adjfine = ptp_ocp_null_adjfine, 124762306a36Sopenharmony_ci .adjphase = ptp_ocp_null_adjphase, 124862306a36Sopenharmony_ci .getmaxphase = ptp_ocp_null_getmaxphase, 124962306a36Sopenharmony_ci .enable = ptp_ocp_enable, 125062306a36Sopenharmony_ci .verify = ptp_ocp_verify, 125162306a36Sopenharmony_ci .pps = true, 125262306a36Sopenharmony_ci .n_ext_ts = 6, 125362306a36Sopenharmony_ci .n_per_out = 5, 125462306a36Sopenharmony_ci}; 125562306a36Sopenharmony_ci 125662306a36Sopenharmony_cistatic void 125762306a36Sopenharmony_ci__ptp_ocp_clear_drift_locked(struct ptp_ocp *bp) 125862306a36Sopenharmony_ci{ 125962306a36Sopenharmony_ci u32 ctrl, select; 126062306a36Sopenharmony_ci 126162306a36Sopenharmony_ci select = ioread32(&bp->reg->select); 126262306a36Sopenharmony_ci iowrite32(OCP_SELECT_CLK_REG, &bp->reg->select); 126362306a36Sopenharmony_ci 126462306a36Sopenharmony_ci iowrite32(0, &bp->reg->drift_ns); 126562306a36Sopenharmony_ci 126662306a36Sopenharmony_ci ctrl = OCP_CTRL_ADJUST_DRIFT | OCP_CTRL_ENABLE; 126762306a36Sopenharmony_ci iowrite32(ctrl, &bp->reg->ctrl); 126862306a36Sopenharmony_ci 126962306a36Sopenharmony_ci /* restore clock selection */ 127062306a36Sopenharmony_ci iowrite32(select >> 16, &bp->reg->select); 127162306a36Sopenharmony_ci} 127262306a36Sopenharmony_ci 127362306a36Sopenharmony_cistatic void 127462306a36Sopenharmony_ciptp_ocp_utc_distribute(struct ptp_ocp *bp, u32 val) 127562306a36Sopenharmony_ci{ 127662306a36Sopenharmony_ci unsigned long flags; 127762306a36Sopenharmony_ci 127862306a36Sopenharmony_ci spin_lock_irqsave(&bp->lock, flags); 127962306a36Sopenharmony_ci 128062306a36Sopenharmony_ci bp->utc_tai_offset = val; 128162306a36Sopenharmony_ci 128262306a36Sopenharmony_ci if (bp->irig_out) 128362306a36Sopenharmony_ci iowrite32(val, &bp->irig_out->adj_sec); 128462306a36Sopenharmony_ci if (bp->dcf_out) 128562306a36Sopenharmony_ci iowrite32(val, &bp->dcf_out->adj_sec); 128662306a36Sopenharmony_ci if (bp->nmea_out) 128762306a36Sopenharmony_ci iowrite32(val, &bp->nmea_out->adj_sec); 128862306a36Sopenharmony_ci 128962306a36Sopenharmony_ci spin_unlock_irqrestore(&bp->lock, flags); 129062306a36Sopenharmony_ci} 129162306a36Sopenharmony_ci 129262306a36Sopenharmony_cistatic void 129362306a36Sopenharmony_ciptp_ocp_watchdog(struct timer_list *t) 129462306a36Sopenharmony_ci{ 129562306a36Sopenharmony_ci struct ptp_ocp *bp = from_timer(bp, t, watchdog); 129662306a36Sopenharmony_ci unsigned long flags; 129762306a36Sopenharmony_ci u32 status, utc_offset; 129862306a36Sopenharmony_ci 129962306a36Sopenharmony_ci status = ioread32(&bp->pps_to_clk->status); 130062306a36Sopenharmony_ci 130162306a36Sopenharmony_ci if (status & PPS_STATUS_SUPERV_ERR) { 130262306a36Sopenharmony_ci iowrite32(status, &bp->pps_to_clk->status); 130362306a36Sopenharmony_ci if (!bp->gnss_lost) { 130462306a36Sopenharmony_ci spin_lock_irqsave(&bp->lock, flags); 130562306a36Sopenharmony_ci __ptp_ocp_clear_drift_locked(bp); 130662306a36Sopenharmony_ci spin_unlock_irqrestore(&bp->lock, flags); 130762306a36Sopenharmony_ci bp->gnss_lost = ktime_get_real_seconds(); 130862306a36Sopenharmony_ci } 130962306a36Sopenharmony_ci 131062306a36Sopenharmony_ci } else if (bp->gnss_lost) { 131162306a36Sopenharmony_ci bp->gnss_lost = 0; 131262306a36Sopenharmony_ci } 131362306a36Sopenharmony_ci 131462306a36Sopenharmony_ci /* if GNSS provides correct data we can rely on 131562306a36Sopenharmony_ci * it to get leap second information 131662306a36Sopenharmony_ci */ 131762306a36Sopenharmony_ci if (bp->tod) { 131862306a36Sopenharmony_ci status = ioread32(&bp->tod->utc_status); 131962306a36Sopenharmony_ci utc_offset = status & TOD_STATUS_UTC_MASK; 132062306a36Sopenharmony_ci if (status & TOD_STATUS_UTC_VALID && 132162306a36Sopenharmony_ci utc_offset != bp->utc_tai_offset) 132262306a36Sopenharmony_ci ptp_ocp_utc_distribute(bp, utc_offset); 132362306a36Sopenharmony_ci } 132462306a36Sopenharmony_ci 132562306a36Sopenharmony_ci mod_timer(&bp->watchdog, jiffies + HZ); 132662306a36Sopenharmony_ci} 132762306a36Sopenharmony_ci 132862306a36Sopenharmony_cistatic void 132962306a36Sopenharmony_ciptp_ocp_estimate_pci_timing(struct ptp_ocp *bp) 133062306a36Sopenharmony_ci{ 133162306a36Sopenharmony_ci ktime_t start, end; 133262306a36Sopenharmony_ci ktime_t delay; 133362306a36Sopenharmony_ci u32 ctrl; 133462306a36Sopenharmony_ci 133562306a36Sopenharmony_ci ctrl = ioread32(&bp->reg->ctrl); 133662306a36Sopenharmony_ci ctrl = OCP_CTRL_READ_TIME_REQ | OCP_CTRL_ENABLE; 133762306a36Sopenharmony_ci 133862306a36Sopenharmony_ci iowrite32(ctrl, &bp->reg->ctrl); 133962306a36Sopenharmony_ci 134062306a36Sopenharmony_ci start = ktime_get_ns(); 134162306a36Sopenharmony_ci 134262306a36Sopenharmony_ci ctrl = ioread32(&bp->reg->ctrl); 134362306a36Sopenharmony_ci 134462306a36Sopenharmony_ci end = ktime_get_ns(); 134562306a36Sopenharmony_ci 134662306a36Sopenharmony_ci delay = end - start; 134762306a36Sopenharmony_ci bp->ts_window_adjust = (delay >> 5) * 3; 134862306a36Sopenharmony_ci} 134962306a36Sopenharmony_ci 135062306a36Sopenharmony_cistatic int 135162306a36Sopenharmony_ciptp_ocp_init_clock(struct ptp_ocp *bp) 135262306a36Sopenharmony_ci{ 135362306a36Sopenharmony_ci struct timespec64 ts; 135462306a36Sopenharmony_ci bool sync; 135562306a36Sopenharmony_ci u32 ctrl; 135662306a36Sopenharmony_ci 135762306a36Sopenharmony_ci ctrl = OCP_CTRL_ENABLE; 135862306a36Sopenharmony_ci iowrite32(ctrl, &bp->reg->ctrl); 135962306a36Sopenharmony_ci 136062306a36Sopenharmony_ci /* NO DRIFT Correction */ 136162306a36Sopenharmony_ci /* offset_p:i 1/8, offset_i: 1/16, drift_p: 0, drift_i: 0 */ 136262306a36Sopenharmony_ci iowrite32(0x2000, &bp->reg->servo_offset_p); 136362306a36Sopenharmony_ci iowrite32(0x1000, &bp->reg->servo_offset_i); 136462306a36Sopenharmony_ci iowrite32(0, &bp->reg->servo_drift_p); 136562306a36Sopenharmony_ci iowrite32(0, &bp->reg->servo_drift_i); 136662306a36Sopenharmony_ci 136762306a36Sopenharmony_ci /* latch servo values */ 136862306a36Sopenharmony_ci ctrl |= OCP_CTRL_ADJUST_SERVO; 136962306a36Sopenharmony_ci iowrite32(ctrl, &bp->reg->ctrl); 137062306a36Sopenharmony_ci 137162306a36Sopenharmony_ci if ((ioread32(&bp->reg->ctrl) & OCP_CTRL_ENABLE) == 0) { 137262306a36Sopenharmony_ci dev_err(&bp->pdev->dev, "clock not enabled\n"); 137362306a36Sopenharmony_ci return -ENODEV; 137462306a36Sopenharmony_ci } 137562306a36Sopenharmony_ci 137662306a36Sopenharmony_ci ptp_ocp_estimate_pci_timing(bp); 137762306a36Sopenharmony_ci 137862306a36Sopenharmony_ci sync = ioread32(&bp->reg->status) & OCP_STATUS_IN_SYNC; 137962306a36Sopenharmony_ci if (!sync) { 138062306a36Sopenharmony_ci ktime_get_clocktai_ts64(&ts); 138162306a36Sopenharmony_ci ptp_ocp_settime(&bp->ptp_info, &ts); 138262306a36Sopenharmony_ci } 138362306a36Sopenharmony_ci 138462306a36Sopenharmony_ci /* If there is a clock supervisor, then enable the watchdog */ 138562306a36Sopenharmony_ci if (bp->pps_to_clk) { 138662306a36Sopenharmony_ci timer_setup(&bp->watchdog, ptp_ocp_watchdog, 0); 138762306a36Sopenharmony_ci mod_timer(&bp->watchdog, jiffies + HZ); 138862306a36Sopenharmony_ci } 138962306a36Sopenharmony_ci 139062306a36Sopenharmony_ci return 0; 139162306a36Sopenharmony_ci} 139262306a36Sopenharmony_ci 139362306a36Sopenharmony_cistatic void 139462306a36Sopenharmony_ciptp_ocp_tod_init(struct ptp_ocp *bp) 139562306a36Sopenharmony_ci{ 139662306a36Sopenharmony_ci u32 ctrl, reg; 139762306a36Sopenharmony_ci 139862306a36Sopenharmony_ci ctrl = ioread32(&bp->tod->ctrl); 139962306a36Sopenharmony_ci ctrl |= TOD_CTRL_PROTOCOL | TOD_CTRL_ENABLE; 140062306a36Sopenharmony_ci ctrl &= ~(TOD_CTRL_DISABLE_FMT_A | TOD_CTRL_DISABLE_FMT_B); 140162306a36Sopenharmony_ci iowrite32(ctrl, &bp->tod->ctrl); 140262306a36Sopenharmony_ci 140362306a36Sopenharmony_ci reg = ioread32(&bp->tod->utc_status); 140462306a36Sopenharmony_ci if (reg & TOD_STATUS_UTC_VALID) 140562306a36Sopenharmony_ci ptp_ocp_utc_distribute(bp, reg & TOD_STATUS_UTC_MASK); 140662306a36Sopenharmony_ci} 140762306a36Sopenharmony_ci 140862306a36Sopenharmony_cistatic const char * 140962306a36Sopenharmony_ciptp_ocp_tod_proto_name(const int idx) 141062306a36Sopenharmony_ci{ 141162306a36Sopenharmony_ci static const char * const proto_name[] = { 141262306a36Sopenharmony_ci "NMEA", "NMEA_ZDA", "NMEA_RMC", "NMEA_none", 141362306a36Sopenharmony_ci "UBX", "UBX_UTC", "UBX_LS", "UBX_none" 141462306a36Sopenharmony_ci }; 141562306a36Sopenharmony_ci return proto_name[idx]; 141662306a36Sopenharmony_ci} 141762306a36Sopenharmony_ci 141862306a36Sopenharmony_cistatic const char * 141962306a36Sopenharmony_ciptp_ocp_tod_gnss_name(int idx) 142062306a36Sopenharmony_ci{ 142162306a36Sopenharmony_ci static const char * const gnss_name[] = { 142262306a36Sopenharmony_ci "ALL", "COMBINED", "GPS", "GLONASS", "GALILEO", "BEIDOU", 142362306a36Sopenharmony_ci "Unknown" 142462306a36Sopenharmony_ci }; 142562306a36Sopenharmony_ci if (idx >= ARRAY_SIZE(gnss_name)) 142662306a36Sopenharmony_ci idx = ARRAY_SIZE(gnss_name) - 1; 142762306a36Sopenharmony_ci return gnss_name[idx]; 142862306a36Sopenharmony_ci} 142962306a36Sopenharmony_ci 143062306a36Sopenharmony_cistruct ptp_ocp_nvmem_match_info { 143162306a36Sopenharmony_ci struct ptp_ocp *bp; 143262306a36Sopenharmony_ci const void * const tag; 143362306a36Sopenharmony_ci}; 143462306a36Sopenharmony_ci 143562306a36Sopenharmony_cistatic int 143662306a36Sopenharmony_ciptp_ocp_nvmem_match(struct device *dev, const void *data) 143762306a36Sopenharmony_ci{ 143862306a36Sopenharmony_ci const struct ptp_ocp_nvmem_match_info *info = data; 143962306a36Sopenharmony_ci 144062306a36Sopenharmony_ci dev = dev->parent; 144162306a36Sopenharmony_ci if (!i2c_verify_client(dev) || info->tag != dev->platform_data) 144262306a36Sopenharmony_ci return 0; 144362306a36Sopenharmony_ci 144462306a36Sopenharmony_ci while ((dev = dev->parent)) 144562306a36Sopenharmony_ci if (dev->driver && !strcmp(dev->driver->name, KBUILD_MODNAME)) 144662306a36Sopenharmony_ci return info->bp == dev_get_drvdata(dev); 144762306a36Sopenharmony_ci return 0; 144862306a36Sopenharmony_ci} 144962306a36Sopenharmony_ci 145062306a36Sopenharmony_cistatic inline struct nvmem_device * 145162306a36Sopenharmony_ciptp_ocp_nvmem_device_get(struct ptp_ocp *bp, const void * const tag) 145262306a36Sopenharmony_ci{ 145362306a36Sopenharmony_ci struct ptp_ocp_nvmem_match_info info = { .bp = bp, .tag = tag }; 145462306a36Sopenharmony_ci 145562306a36Sopenharmony_ci return nvmem_device_find(&info, ptp_ocp_nvmem_match); 145662306a36Sopenharmony_ci} 145762306a36Sopenharmony_ci 145862306a36Sopenharmony_cistatic inline void 145962306a36Sopenharmony_ciptp_ocp_nvmem_device_put(struct nvmem_device **nvmemp) 146062306a36Sopenharmony_ci{ 146162306a36Sopenharmony_ci if (!IS_ERR_OR_NULL(*nvmemp)) 146262306a36Sopenharmony_ci nvmem_device_put(*nvmemp); 146362306a36Sopenharmony_ci *nvmemp = NULL; 146462306a36Sopenharmony_ci} 146562306a36Sopenharmony_ci 146662306a36Sopenharmony_cistatic void 146762306a36Sopenharmony_ciptp_ocp_read_eeprom(struct ptp_ocp *bp) 146862306a36Sopenharmony_ci{ 146962306a36Sopenharmony_ci const struct ptp_ocp_eeprom_map *map; 147062306a36Sopenharmony_ci struct nvmem_device *nvmem; 147162306a36Sopenharmony_ci const void *tag; 147262306a36Sopenharmony_ci int ret; 147362306a36Sopenharmony_ci 147462306a36Sopenharmony_ci if (!bp->i2c_ctrl) 147562306a36Sopenharmony_ci return; 147662306a36Sopenharmony_ci 147762306a36Sopenharmony_ci tag = NULL; 147862306a36Sopenharmony_ci nvmem = NULL; 147962306a36Sopenharmony_ci 148062306a36Sopenharmony_ci for (map = bp->eeprom_map; map->len; map++) { 148162306a36Sopenharmony_ci if (map->tag != tag) { 148262306a36Sopenharmony_ci tag = map->tag; 148362306a36Sopenharmony_ci ptp_ocp_nvmem_device_put(&nvmem); 148462306a36Sopenharmony_ci } 148562306a36Sopenharmony_ci if (!nvmem) { 148662306a36Sopenharmony_ci nvmem = ptp_ocp_nvmem_device_get(bp, tag); 148762306a36Sopenharmony_ci if (IS_ERR(nvmem)) { 148862306a36Sopenharmony_ci ret = PTR_ERR(nvmem); 148962306a36Sopenharmony_ci goto fail; 149062306a36Sopenharmony_ci } 149162306a36Sopenharmony_ci } 149262306a36Sopenharmony_ci ret = nvmem_device_read(nvmem, map->off, map->len, 149362306a36Sopenharmony_ci BP_MAP_ENTRY_ADDR(bp, map)); 149462306a36Sopenharmony_ci if (ret != map->len) 149562306a36Sopenharmony_ci goto fail; 149662306a36Sopenharmony_ci } 149762306a36Sopenharmony_ci 149862306a36Sopenharmony_ci bp->has_eeprom_data = true; 149962306a36Sopenharmony_ci 150062306a36Sopenharmony_ciout: 150162306a36Sopenharmony_ci ptp_ocp_nvmem_device_put(&nvmem); 150262306a36Sopenharmony_ci return; 150362306a36Sopenharmony_ci 150462306a36Sopenharmony_cifail: 150562306a36Sopenharmony_ci dev_err(&bp->pdev->dev, "could not read eeprom: %d\n", ret); 150662306a36Sopenharmony_ci goto out; 150762306a36Sopenharmony_ci} 150862306a36Sopenharmony_ci 150962306a36Sopenharmony_cistatic struct device * 151062306a36Sopenharmony_ciptp_ocp_find_flash(struct ptp_ocp *bp) 151162306a36Sopenharmony_ci{ 151262306a36Sopenharmony_ci struct device *dev, *last; 151362306a36Sopenharmony_ci 151462306a36Sopenharmony_ci last = NULL; 151562306a36Sopenharmony_ci dev = &bp->spi_flash->dev; 151662306a36Sopenharmony_ci 151762306a36Sopenharmony_ci while ((dev = device_find_any_child(dev))) { 151862306a36Sopenharmony_ci if (!strcmp("mtd", dev_bus_name(dev))) 151962306a36Sopenharmony_ci break; 152062306a36Sopenharmony_ci put_device(last); 152162306a36Sopenharmony_ci last = dev; 152262306a36Sopenharmony_ci } 152362306a36Sopenharmony_ci put_device(last); 152462306a36Sopenharmony_ci 152562306a36Sopenharmony_ci return dev; 152662306a36Sopenharmony_ci} 152762306a36Sopenharmony_ci 152862306a36Sopenharmony_cistatic int 152962306a36Sopenharmony_ciptp_ocp_devlink_fw_image(struct devlink *devlink, const struct firmware *fw, 153062306a36Sopenharmony_ci const u8 **data, size_t *size) 153162306a36Sopenharmony_ci{ 153262306a36Sopenharmony_ci struct ptp_ocp *bp = devlink_priv(devlink); 153362306a36Sopenharmony_ci const struct ptp_ocp_firmware_header *hdr; 153462306a36Sopenharmony_ci size_t offset, length; 153562306a36Sopenharmony_ci u16 crc; 153662306a36Sopenharmony_ci 153762306a36Sopenharmony_ci hdr = (const struct ptp_ocp_firmware_header *)fw->data; 153862306a36Sopenharmony_ci if (memcmp(hdr->magic, OCP_FIRMWARE_MAGIC_HEADER, 4)) { 153962306a36Sopenharmony_ci devlink_flash_update_status_notify(devlink, 154062306a36Sopenharmony_ci "No firmware header found, cancel firmware upgrade", 154162306a36Sopenharmony_ci NULL, 0, 0); 154262306a36Sopenharmony_ci return -EINVAL; 154362306a36Sopenharmony_ci } 154462306a36Sopenharmony_ci 154562306a36Sopenharmony_ci if (be16_to_cpu(hdr->pci_vendor_id) != bp->pdev->vendor || 154662306a36Sopenharmony_ci be16_to_cpu(hdr->pci_device_id) != bp->pdev->device) { 154762306a36Sopenharmony_ci devlink_flash_update_status_notify(devlink, 154862306a36Sopenharmony_ci "Firmware image compatibility check failed", 154962306a36Sopenharmony_ci NULL, 0, 0); 155062306a36Sopenharmony_ci return -EINVAL; 155162306a36Sopenharmony_ci } 155262306a36Sopenharmony_ci 155362306a36Sopenharmony_ci offset = sizeof(*hdr); 155462306a36Sopenharmony_ci length = be32_to_cpu(hdr->image_size); 155562306a36Sopenharmony_ci if (length != (fw->size - offset)) { 155662306a36Sopenharmony_ci devlink_flash_update_status_notify(devlink, 155762306a36Sopenharmony_ci "Firmware image size check failed", 155862306a36Sopenharmony_ci NULL, 0, 0); 155962306a36Sopenharmony_ci return -EINVAL; 156062306a36Sopenharmony_ci } 156162306a36Sopenharmony_ci 156262306a36Sopenharmony_ci crc = crc16(0xffff, &fw->data[offset], length); 156362306a36Sopenharmony_ci if (be16_to_cpu(hdr->crc) != crc) { 156462306a36Sopenharmony_ci devlink_flash_update_status_notify(devlink, 156562306a36Sopenharmony_ci "Firmware image CRC check failed", 156662306a36Sopenharmony_ci NULL, 0, 0); 156762306a36Sopenharmony_ci return -EINVAL; 156862306a36Sopenharmony_ci } 156962306a36Sopenharmony_ci 157062306a36Sopenharmony_ci *data = &fw->data[offset]; 157162306a36Sopenharmony_ci *size = length; 157262306a36Sopenharmony_ci 157362306a36Sopenharmony_ci return 0; 157462306a36Sopenharmony_ci} 157562306a36Sopenharmony_ci 157662306a36Sopenharmony_cistatic int 157762306a36Sopenharmony_ciptp_ocp_devlink_flash(struct devlink *devlink, struct device *dev, 157862306a36Sopenharmony_ci const struct firmware *fw) 157962306a36Sopenharmony_ci{ 158062306a36Sopenharmony_ci struct mtd_info *mtd = dev_get_drvdata(dev); 158162306a36Sopenharmony_ci struct ptp_ocp *bp = devlink_priv(devlink); 158262306a36Sopenharmony_ci size_t off, len, size, resid, wrote; 158362306a36Sopenharmony_ci struct erase_info erase; 158462306a36Sopenharmony_ci size_t base, blksz; 158562306a36Sopenharmony_ci const u8 *data; 158662306a36Sopenharmony_ci int err; 158762306a36Sopenharmony_ci 158862306a36Sopenharmony_ci err = ptp_ocp_devlink_fw_image(devlink, fw, &data, &size); 158962306a36Sopenharmony_ci if (err) 159062306a36Sopenharmony_ci goto out; 159162306a36Sopenharmony_ci 159262306a36Sopenharmony_ci off = 0; 159362306a36Sopenharmony_ci base = bp->flash_start; 159462306a36Sopenharmony_ci blksz = 4096; 159562306a36Sopenharmony_ci resid = size; 159662306a36Sopenharmony_ci 159762306a36Sopenharmony_ci while (resid) { 159862306a36Sopenharmony_ci devlink_flash_update_status_notify(devlink, "Flashing", 159962306a36Sopenharmony_ci NULL, off, size); 160062306a36Sopenharmony_ci 160162306a36Sopenharmony_ci len = min_t(size_t, resid, blksz); 160262306a36Sopenharmony_ci erase.addr = base + off; 160362306a36Sopenharmony_ci erase.len = blksz; 160462306a36Sopenharmony_ci 160562306a36Sopenharmony_ci err = mtd_erase(mtd, &erase); 160662306a36Sopenharmony_ci if (err) 160762306a36Sopenharmony_ci goto out; 160862306a36Sopenharmony_ci 160962306a36Sopenharmony_ci err = mtd_write(mtd, base + off, len, &wrote, data + off); 161062306a36Sopenharmony_ci if (err) 161162306a36Sopenharmony_ci goto out; 161262306a36Sopenharmony_ci 161362306a36Sopenharmony_ci off += blksz; 161462306a36Sopenharmony_ci resid -= len; 161562306a36Sopenharmony_ci } 161662306a36Sopenharmony_ciout: 161762306a36Sopenharmony_ci return err; 161862306a36Sopenharmony_ci} 161962306a36Sopenharmony_ci 162062306a36Sopenharmony_cistatic int 162162306a36Sopenharmony_ciptp_ocp_devlink_flash_update(struct devlink *devlink, 162262306a36Sopenharmony_ci struct devlink_flash_update_params *params, 162362306a36Sopenharmony_ci struct netlink_ext_ack *extack) 162462306a36Sopenharmony_ci{ 162562306a36Sopenharmony_ci struct ptp_ocp *bp = devlink_priv(devlink); 162662306a36Sopenharmony_ci struct device *dev; 162762306a36Sopenharmony_ci const char *msg; 162862306a36Sopenharmony_ci int err; 162962306a36Sopenharmony_ci 163062306a36Sopenharmony_ci dev = ptp_ocp_find_flash(bp); 163162306a36Sopenharmony_ci if (!dev) { 163262306a36Sopenharmony_ci dev_err(&bp->pdev->dev, "Can't find Flash SPI adapter\n"); 163362306a36Sopenharmony_ci return -ENODEV; 163462306a36Sopenharmony_ci } 163562306a36Sopenharmony_ci 163662306a36Sopenharmony_ci devlink_flash_update_status_notify(devlink, "Preparing to flash", 163762306a36Sopenharmony_ci NULL, 0, 0); 163862306a36Sopenharmony_ci 163962306a36Sopenharmony_ci err = ptp_ocp_devlink_flash(devlink, dev, params->fw); 164062306a36Sopenharmony_ci 164162306a36Sopenharmony_ci msg = err ? "Flash error" : "Flash complete"; 164262306a36Sopenharmony_ci devlink_flash_update_status_notify(devlink, msg, NULL, 0, 0); 164362306a36Sopenharmony_ci 164462306a36Sopenharmony_ci put_device(dev); 164562306a36Sopenharmony_ci return err; 164662306a36Sopenharmony_ci} 164762306a36Sopenharmony_ci 164862306a36Sopenharmony_cistatic int 164962306a36Sopenharmony_ciptp_ocp_devlink_info_get(struct devlink *devlink, struct devlink_info_req *req, 165062306a36Sopenharmony_ci struct netlink_ext_ack *extack) 165162306a36Sopenharmony_ci{ 165262306a36Sopenharmony_ci struct ptp_ocp *bp = devlink_priv(devlink); 165362306a36Sopenharmony_ci const char *fw_image; 165462306a36Sopenharmony_ci char buf[32]; 165562306a36Sopenharmony_ci int err; 165662306a36Sopenharmony_ci 165762306a36Sopenharmony_ci fw_image = bp->fw_loader ? "loader" : "fw"; 165862306a36Sopenharmony_ci sprintf(buf, "%d.%d", bp->fw_tag, bp->fw_version); 165962306a36Sopenharmony_ci err = devlink_info_version_running_put(req, fw_image, buf); 166062306a36Sopenharmony_ci if (err) 166162306a36Sopenharmony_ci return err; 166262306a36Sopenharmony_ci 166362306a36Sopenharmony_ci if (!bp->has_eeprom_data) { 166462306a36Sopenharmony_ci ptp_ocp_read_eeprom(bp); 166562306a36Sopenharmony_ci if (!bp->has_eeprom_data) 166662306a36Sopenharmony_ci return 0; 166762306a36Sopenharmony_ci } 166862306a36Sopenharmony_ci 166962306a36Sopenharmony_ci sprintf(buf, "%pM", bp->serial); 167062306a36Sopenharmony_ci err = devlink_info_serial_number_put(req, buf); 167162306a36Sopenharmony_ci if (err) 167262306a36Sopenharmony_ci return err; 167362306a36Sopenharmony_ci 167462306a36Sopenharmony_ci err = devlink_info_version_fixed_put(req, 167562306a36Sopenharmony_ci DEVLINK_INFO_VERSION_GENERIC_BOARD_ID, 167662306a36Sopenharmony_ci bp->board_id); 167762306a36Sopenharmony_ci if (err) 167862306a36Sopenharmony_ci return err; 167962306a36Sopenharmony_ci 168062306a36Sopenharmony_ci return 0; 168162306a36Sopenharmony_ci} 168262306a36Sopenharmony_ci 168362306a36Sopenharmony_cistatic const struct devlink_ops ptp_ocp_devlink_ops = { 168462306a36Sopenharmony_ci .flash_update = ptp_ocp_devlink_flash_update, 168562306a36Sopenharmony_ci .info_get = ptp_ocp_devlink_info_get, 168662306a36Sopenharmony_ci}; 168762306a36Sopenharmony_ci 168862306a36Sopenharmony_cistatic void __iomem * 168962306a36Sopenharmony_ci__ptp_ocp_get_mem(struct ptp_ocp *bp, resource_size_t start, int size) 169062306a36Sopenharmony_ci{ 169162306a36Sopenharmony_ci struct resource res = DEFINE_RES_MEM_NAMED(start, size, "ptp_ocp"); 169262306a36Sopenharmony_ci 169362306a36Sopenharmony_ci return devm_ioremap_resource(&bp->pdev->dev, &res); 169462306a36Sopenharmony_ci} 169562306a36Sopenharmony_ci 169662306a36Sopenharmony_cistatic void __iomem * 169762306a36Sopenharmony_ciptp_ocp_get_mem(struct ptp_ocp *bp, struct ocp_resource *r) 169862306a36Sopenharmony_ci{ 169962306a36Sopenharmony_ci resource_size_t start; 170062306a36Sopenharmony_ci 170162306a36Sopenharmony_ci start = pci_resource_start(bp->pdev, 0) + r->offset; 170262306a36Sopenharmony_ci return __ptp_ocp_get_mem(bp, start, r->size); 170362306a36Sopenharmony_ci} 170462306a36Sopenharmony_ci 170562306a36Sopenharmony_cistatic void 170662306a36Sopenharmony_ciptp_ocp_set_irq_resource(struct resource *res, int irq) 170762306a36Sopenharmony_ci{ 170862306a36Sopenharmony_ci struct resource r = DEFINE_RES_IRQ(irq); 170962306a36Sopenharmony_ci *res = r; 171062306a36Sopenharmony_ci} 171162306a36Sopenharmony_ci 171262306a36Sopenharmony_cistatic void 171362306a36Sopenharmony_ciptp_ocp_set_mem_resource(struct resource *res, resource_size_t start, int size) 171462306a36Sopenharmony_ci{ 171562306a36Sopenharmony_ci struct resource r = DEFINE_RES_MEM(start, size); 171662306a36Sopenharmony_ci *res = r; 171762306a36Sopenharmony_ci} 171862306a36Sopenharmony_ci 171962306a36Sopenharmony_cistatic int 172062306a36Sopenharmony_ciptp_ocp_register_spi(struct ptp_ocp *bp, struct ocp_resource *r) 172162306a36Sopenharmony_ci{ 172262306a36Sopenharmony_ci struct ptp_ocp_flash_info *info; 172362306a36Sopenharmony_ci struct pci_dev *pdev = bp->pdev; 172462306a36Sopenharmony_ci struct platform_device *p; 172562306a36Sopenharmony_ci struct resource res[2]; 172662306a36Sopenharmony_ci resource_size_t start; 172762306a36Sopenharmony_ci int id; 172862306a36Sopenharmony_ci 172962306a36Sopenharmony_ci start = pci_resource_start(pdev, 0) + r->offset; 173062306a36Sopenharmony_ci ptp_ocp_set_mem_resource(&res[0], start, r->size); 173162306a36Sopenharmony_ci ptp_ocp_set_irq_resource(&res[1], pci_irq_vector(pdev, r->irq_vec)); 173262306a36Sopenharmony_ci 173362306a36Sopenharmony_ci info = r->extra; 173462306a36Sopenharmony_ci id = pci_dev_id(pdev) << 1; 173562306a36Sopenharmony_ci id += info->pci_offset; 173662306a36Sopenharmony_ci 173762306a36Sopenharmony_ci p = platform_device_register_resndata(&pdev->dev, info->name, id, 173862306a36Sopenharmony_ci res, 2, info->data, 173962306a36Sopenharmony_ci info->data_size); 174062306a36Sopenharmony_ci if (IS_ERR(p)) 174162306a36Sopenharmony_ci return PTR_ERR(p); 174262306a36Sopenharmony_ci 174362306a36Sopenharmony_ci bp_assign_entry(bp, r, p); 174462306a36Sopenharmony_ci 174562306a36Sopenharmony_ci return 0; 174662306a36Sopenharmony_ci} 174762306a36Sopenharmony_ci 174862306a36Sopenharmony_cistatic struct platform_device * 174962306a36Sopenharmony_ciptp_ocp_i2c_bus(struct pci_dev *pdev, struct ocp_resource *r, int id) 175062306a36Sopenharmony_ci{ 175162306a36Sopenharmony_ci struct ptp_ocp_i2c_info *info; 175262306a36Sopenharmony_ci struct resource res[2]; 175362306a36Sopenharmony_ci resource_size_t start; 175462306a36Sopenharmony_ci 175562306a36Sopenharmony_ci info = r->extra; 175662306a36Sopenharmony_ci start = pci_resource_start(pdev, 0) + r->offset; 175762306a36Sopenharmony_ci ptp_ocp_set_mem_resource(&res[0], start, r->size); 175862306a36Sopenharmony_ci ptp_ocp_set_irq_resource(&res[1], pci_irq_vector(pdev, r->irq_vec)); 175962306a36Sopenharmony_ci 176062306a36Sopenharmony_ci return platform_device_register_resndata(&pdev->dev, info->name, 176162306a36Sopenharmony_ci id, res, 2, 176262306a36Sopenharmony_ci info->data, info->data_size); 176362306a36Sopenharmony_ci} 176462306a36Sopenharmony_ci 176562306a36Sopenharmony_cistatic int 176662306a36Sopenharmony_ciptp_ocp_register_i2c(struct ptp_ocp *bp, struct ocp_resource *r) 176762306a36Sopenharmony_ci{ 176862306a36Sopenharmony_ci struct pci_dev *pdev = bp->pdev; 176962306a36Sopenharmony_ci struct ptp_ocp_i2c_info *info; 177062306a36Sopenharmony_ci struct platform_device *p; 177162306a36Sopenharmony_ci struct clk_hw *clk; 177262306a36Sopenharmony_ci char buf[32]; 177362306a36Sopenharmony_ci int id; 177462306a36Sopenharmony_ci 177562306a36Sopenharmony_ci info = r->extra; 177662306a36Sopenharmony_ci id = pci_dev_id(bp->pdev); 177762306a36Sopenharmony_ci 177862306a36Sopenharmony_ci sprintf(buf, "AXI.%d", id); 177962306a36Sopenharmony_ci clk = clk_hw_register_fixed_rate(&pdev->dev, buf, NULL, 0, 178062306a36Sopenharmony_ci info->fixed_rate); 178162306a36Sopenharmony_ci if (IS_ERR(clk)) 178262306a36Sopenharmony_ci return PTR_ERR(clk); 178362306a36Sopenharmony_ci bp->i2c_clk = clk; 178462306a36Sopenharmony_ci 178562306a36Sopenharmony_ci sprintf(buf, "%s.%d", info->name, id); 178662306a36Sopenharmony_ci devm_clk_hw_register_clkdev(&pdev->dev, clk, NULL, buf); 178762306a36Sopenharmony_ci p = ptp_ocp_i2c_bus(bp->pdev, r, id); 178862306a36Sopenharmony_ci if (IS_ERR(p)) 178962306a36Sopenharmony_ci return PTR_ERR(p); 179062306a36Sopenharmony_ci 179162306a36Sopenharmony_ci bp_assign_entry(bp, r, p); 179262306a36Sopenharmony_ci 179362306a36Sopenharmony_ci return 0; 179462306a36Sopenharmony_ci} 179562306a36Sopenharmony_ci 179662306a36Sopenharmony_ci/* The expectation is that this is triggered only on error. */ 179762306a36Sopenharmony_cistatic irqreturn_t 179862306a36Sopenharmony_ciptp_ocp_signal_irq(int irq, void *priv) 179962306a36Sopenharmony_ci{ 180062306a36Sopenharmony_ci struct ptp_ocp_ext_src *ext = priv; 180162306a36Sopenharmony_ci struct signal_reg __iomem *reg = ext->mem; 180262306a36Sopenharmony_ci struct ptp_ocp *bp = ext->bp; 180362306a36Sopenharmony_ci u32 enable, status; 180462306a36Sopenharmony_ci int gen; 180562306a36Sopenharmony_ci 180662306a36Sopenharmony_ci gen = ext->info->index - 1; 180762306a36Sopenharmony_ci 180862306a36Sopenharmony_ci enable = ioread32(®->enable); 180962306a36Sopenharmony_ci status = ioread32(®->status); 181062306a36Sopenharmony_ci 181162306a36Sopenharmony_ci /* disable generator on error */ 181262306a36Sopenharmony_ci if (status || !enable) { 181362306a36Sopenharmony_ci iowrite32(0, ®->intr_mask); 181462306a36Sopenharmony_ci iowrite32(0, ®->enable); 181562306a36Sopenharmony_ci bp->signal[gen].running = false; 181662306a36Sopenharmony_ci } 181762306a36Sopenharmony_ci 181862306a36Sopenharmony_ci iowrite32(0, ®->intr); /* ack interrupt */ 181962306a36Sopenharmony_ci 182062306a36Sopenharmony_ci return IRQ_HANDLED; 182162306a36Sopenharmony_ci} 182262306a36Sopenharmony_ci 182362306a36Sopenharmony_cistatic int 182462306a36Sopenharmony_ciptp_ocp_signal_set(struct ptp_ocp *bp, int gen, struct ptp_ocp_signal *s) 182562306a36Sopenharmony_ci{ 182662306a36Sopenharmony_ci struct ptp_system_timestamp sts; 182762306a36Sopenharmony_ci struct timespec64 ts; 182862306a36Sopenharmony_ci ktime_t start_ns; 182962306a36Sopenharmony_ci int err; 183062306a36Sopenharmony_ci 183162306a36Sopenharmony_ci if (!s->period) 183262306a36Sopenharmony_ci return 0; 183362306a36Sopenharmony_ci 183462306a36Sopenharmony_ci if (!s->pulse) 183562306a36Sopenharmony_ci s->pulse = ktime_divns(s->period * s->duty, 100); 183662306a36Sopenharmony_ci 183762306a36Sopenharmony_ci err = ptp_ocp_gettimex(&bp->ptp_info, &ts, &sts); 183862306a36Sopenharmony_ci if (err) 183962306a36Sopenharmony_ci return err; 184062306a36Sopenharmony_ci 184162306a36Sopenharmony_ci start_ns = ktime_set(ts.tv_sec, ts.tv_nsec) + NSEC_PER_MSEC; 184262306a36Sopenharmony_ci if (!s->start) { 184362306a36Sopenharmony_ci /* roundup() does not work on 32-bit systems */ 184462306a36Sopenharmony_ci s->start = DIV64_U64_ROUND_UP(start_ns, s->period); 184562306a36Sopenharmony_ci s->start = ktime_add(s->start, s->phase); 184662306a36Sopenharmony_ci } 184762306a36Sopenharmony_ci 184862306a36Sopenharmony_ci if (s->duty < 1 || s->duty > 99) 184962306a36Sopenharmony_ci return -EINVAL; 185062306a36Sopenharmony_ci 185162306a36Sopenharmony_ci if (s->pulse < 1 || s->pulse > s->period) 185262306a36Sopenharmony_ci return -EINVAL; 185362306a36Sopenharmony_ci 185462306a36Sopenharmony_ci if (s->start < start_ns) 185562306a36Sopenharmony_ci return -EINVAL; 185662306a36Sopenharmony_ci 185762306a36Sopenharmony_ci bp->signal[gen] = *s; 185862306a36Sopenharmony_ci 185962306a36Sopenharmony_ci return 0; 186062306a36Sopenharmony_ci} 186162306a36Sopenharmony_ci 186262306a36Sopenharmony_cistatic int 186362306a36Sopenharmony_ciptp_ocp_signal_from_perout(struct ptp_ocp *bp, int gen, 186462306a36Sopenharmony_ci struct ptp_perout_request *req) 186562306a36Sopenharmony_ci{ 186662306a36Sopenharmony_ci struct ptp_ocp_signal s = { }; 186762306a36Sopenharmony_ci 186862306a36Sopenharmony_ci s.polarity = bp->signal[gen].polarity; 186962306a36Sopenharmony_ci s.period = ktime_set(req->period.sec, req->period.nsec); 187062306a36Sopenharmony_ci if (!s.period) 187162306a36Sopenharmony_ci return 0; 187262306a36Sopenharmony_ci 187362306a36Sopenharmony_ci if (req->flags & PTP_PEROUT_DUTY_CYCLE) { 187462306a36Sopenharmony_ci s.pulse = ktime_set(req->on.sec, req->on.nsec); 187562306a36Sopenharmony_ci s.duty = ktime_divns(s.pulse * 100, s.period); 187662306a36Sopenharmony_ci } 187762306a36Sopenharmony_ci 187862306a36Sopenharmony_ci if (req->flags & PTP_PEROUT_PHASE) 187962306a36Sopenharmony_ci s.phase = ktime_set(req->phase.sec, req->phase.nsec); 188062306a36Sopenharmony_ci else 188162306a36Sopenharmony_ci s.start = ktime_set(req->start.sec, req->start.nsec); 188262306a36Sopenharmony_ci 188362306a36Sopenharmony_ci return ptp_ocp_signal_set(bp, gen, &s); 188462306a36Sopenharmony_ci} 188562306a36Sopenharmony_ci 188662306a36Sopenharmony_cistatic int 188762306a36Sopenharmony_ciptp_ocp_signal_enable(void *priv, u32 req, bool enable) 188862306a36Sopenharmony_ci{ 188962306a36Sopenharmony_ci struct ptp_ocp_ext_src *ext = priv; 189062306a36Sopenharmony_ci struct signal_reg __iomem *reg = ext->mem; 189162306a36Sopenharmony_ci struct ptp_ocp *bp = ext->bp; 189262306a36Sopenharmony_ci struct timespec64 ts; 189362306a36Sopenharmony_ci int gen; 189462306a36Sopenharmony_ci 189562306a36Sopenharmony_ci gen = ext->info->index - 1; 189662306a36Sopenharmony_ci 189762306a36Sopenharmony_ci iowrite32(0, ®->intr_mask); 189862306a36Sopenharmony_ci iowrite32(0, ®->enable); 189962306a36Sopenharmony_ci bp->signal[gen].running = false; 190062306a36Sopenharmony_ci if (!enable) 190162306a36Sopenharmony_ci return 0; 190262306a36Sopenharmony_ci 190362306a36Sopenharmony_ci ts = ktime_to_timespec64(bp->signal[gen].start); 190462306a36Sopenharmony_ci iowrite32(ts.tv_sec, ®->start_sec); 190562306a36Sopenharmony_ci iowrite32(ts.tv_nsec, ®->start_ns); 190662306a36Sopenharmony_ci 190762306a36Sopenharmony_ci ts = ktime_to_timespec64(bp->signal[gen].period); 190862306a36Sopenharmony_ci iowrite32(ts.tv_sec, ®->period_sec); 190962306a36Sopenharmony_ci iowrite32(ts.tv_nsec, ®->period_ns); 191062306a36Sopenharmony_ci 191162306a36Sopenharmony_ci ts = ktime_to_timespec64(bp->signal[gen].pulse); 191262306a36Sopenharmony_ci iowrite32(ts.tv_sec, ®->pulse_sec); 191362306a36Sopenharmony_ci iowrite32(ts.tv_nsec, ®->pulse_ns); 191462306a36Sopenharmony_ci 191562306a36Sopenharmony_ci iowrite32(bp->signal[gen].polarity, ®->polarity); 191662306a36Sopenharmony_ci iowrite32(0, ®->repeat_count); 191762306a36Sopenharmony_ci 191862306a36Sopenharmony_ci iowrite32(0, ®->intr); /* clear interrupt state */ 191962306a36Sopenharmony_ci iowrite32(1, ®->intr_mask); /* enable interrupt */ 192062306a36Sopenharmony_ci iowrite32(3, ®->enable); /* valid & enable */ 192162306a36Sopenharmony_ci 192262306a36Sopenharmony_ci bp->signal[gen].running = true; 192362306a36Sopenharmony_ci 192462306a36Sopenharmony_ci return 0; 192562306a36Sopenharmony_ci} 192662306a36Sopenharmony_ci 192762306a36Sopenharmony_cistatic irqreturn_t 192862306a36Sopenharmony_ciptp_ocp_ts_irq(int irq, void *priv) 192962306a36Sopenharmony_ci{ 193062306a36Sopenharmony_ci struct ptp_ocp_ext_src *ext = priv; 193162306a36Sopenharmony_ci struct ts_reg __iomem *reg = ext->mem; 193262306a36Sopenharmony_ci struct ptp_clock_event ev; 193362306a36Sopenharmony_ci u32 sec, nsec; 193462306a36Sopenharmony_ci 193562306a36Sopenharmony_ci if (ext == ext->bp->pps) { 193662306a36Sopenharmony_ci if (ext->bp->pps_req_map & OCP_REQ_PPS) { 193762306a36Sopenharmony_ci ev.type = PTP_CLOCK_PPS; 193862306a36Sopenharmony_ci ptp_clock_event(ext->bp->ptp, &ev); 193962306a36Sopenharmony_ci } 194062306a36Sopenharmony_ci 194162306a36Sopenharmony_ci if ((ext->bp->pps_req_map & ~OCP_REQ_PPS) == 0) 194262306a36Sopenharmony_ci goto out; 194362306a36Sopenharmony_ci } 194462306a36Sopenharmony_ci 194562306a36Sopenharmony_ci /* XXX should fix API - this converts s/ns -> ts -> s/ns */ 194662306a36Sopenharmony_ci sec = ioread32(®->time_sec); 194762306a36Sopenharmony_ci nsec = ioread32(®->time_ns); 194862306a36Sopenharmony_ci 194962306a36Sopenharmony_ci ev.type = PTP_CLOCK_EXTTS; 195062306a36Sopenharmony_ci ev.index = ext->info->index; 195162306a36Sopenharmony_ci ev.timestamp = sec * NSEC_PER_SEC + nsec; 195262306a36Sopenharmony_ci 195362306a36Sopenharmony_ci ptp_clock_event(ext->bp->ptp, &ev); 195462306a36Sopenharmony_ci 195562306a36Sopenharmony_ciout: 195662306a36Sopenharmony_ci iowrite32(1, ®->intr); /* write 1 to ack */ 195762306a36Sopenharmony_ci 195862306a36Sopenharmony_ci return IRQ_HANDLED; 195962306a36Sopenharmony_ci} 196062306a36Sopenharmony_ci 196162306a36Sopenharmony_cistatic int 196262306a36Sopenharmony_ciptp_ocp_ts_enable(void *priv, u32 req, bool enable) 196362306a36Sopenharmony_ci{ 196462306a36Sopenharmony_ci struct ptp_ocp_ext_src *ext = priv; 196562306a36Sopenharmony_ci struct ts_reg __iomem *reg = ext->mem; 196662306a36Sopenharmony_ci struct ptp_ocp *bp = ext->bp; 196762306a36Sopenharmony_ci 196862306a36Sopenharmony_ci if (ext == bp->pps) { 196962306a36Sopenharmony_ci u32 old_map = bp->pps_req_map; 197062306a36Sopenharmony_ci 197162306a36Sopenharmony_ci if (enable) 197262306a36Sopenharmony_ci bp->pps_req_map |= req; 197362306a36Sopenharmony_ci else 197462306a36Sopenharmony_ci bp->pps_req_map &= ~req; 197562306a36Sopenharmony_ci 197662306a36Sopenharmony_ci /* if no state change, just return */ 197762306a36Sopenharmony_ci if ((!!old_map ^ !!bp->pps_req_map) == 0) 197862306a36Sopenharmony_ci return 0; 197962306a36Sopenharmony_ci } 198062306a36Sopenharmony_ci 198162306a36Sopenharmony_ci if (enable) { 198262306a36Sopenharmony_ci iowrite32(1, ®->enable); 198362306a36Sopenharmony_ci iowrite32(1, ®->intr_mask); 198462306a36Sopenharmony_ci iowrite32(1, ®->intr); 198562306a36Sopenharmony_ci } else { 198662306a36Sopenharmony_ci iowrite32(0, ®->intr_mask); 198762306a36Sopenharmony_ci iowrite32(0, ®->enable); 198862306a36Sopenharmony_ci } 198962306a36Sopenharmony_ci 199062306a36Sopenharmony_ci return 0; 199162306a36Sopenharmony_ci} 199262306a36Sopenharmony_ci 199362306a36Sopenharmony_cistatic void 199462306a36Sopenharmony_ciptp_ocp_unregister_ext(struct ptp_ocp_ext_src *ext) 199562306a36Sopenharmony_ci{ 199662306a36Sopenharmony_ci ext->info->enable(ext, ~0, false); 199762306a36Sopenharmony_ci pci_free_irq(ext->bp->pdev, ext->irq_vec, ext); 199862306a36Sopenharmony_ci kfree(ext); 199962306a36Sopenharmony_ci} 200062306a36Sopenharmony_ci 200162306a36Sopenharmony_cistatic int 200262306a36Sopenharmony_ciptp_ocp_register_ext(struct ptp_ocp *bp, struct ocp_resource *r) 200362306a36Sopenharmony_ci{ 200462306a36Sopenharmony_ci struct pci_dev *pdev = bp->pdev; 200562306a36Sopenharmony_ci struct ptp_ocp_ext_src *ext; 200662306a36Sopenharmony_ci int err; 200762306a36Sopenharmony_ci 200862306a36Sopenharmony_ci ext = kzalloc(sizeof(*ext), GFP_KERNEL); 200962306a36Sopenharmony_ci if (!ext) 201062306a36Sopenharmony_ci return -ENOMEM; 201162306a36Sopenharmony_ci 201262306a36Sopenharmony_ci ext->mem = ptp_ocp_get_mem(bp, r); 201362306a36Sopenharmony_ci if (IS_ERR(ext->mem)) { 201462306a36Sopenharmony_ci err = PTR_ERR(ext->mem); 201562306a36Sopenharmony_ci goto out; 201662306a36Sopenharmony_ci } 201762306a36Sopenharmony_ci 201862306a36Sopenharmony_ci ext->bp = bp; 201962306a36Sopenharmony_ci ext->info = r->extra; 202062306a36Sopenharmony_ci ext->irq_vec = r->irq_vec; 202162306a36Sopenharmony_ci 202262306a36Sopenharmony_ci err = pci_request_irq(pdev, r->irq_vec, ext->info->irq_fcn, NULL, 202362306a36Sopenharmony_ci ext, "ocp%d.%s", bp->id, r->name); 202462306a36Sopenharmony_ci if (err) { 202562306a36Sopenharmony_ci dev_err(&pdev->dev, "Could not get irq %d\n", r->irq_vec); 202662306a36Sopenharmony_ci goto out; 202762306a36Sopenharmony_ci } 202862306a36Sopenharmony_ci 202962306a36Sopenharmony_ci bp_assign_entry(bp, r, ext); 203062306a36Sopenharmony_ci 203162306a36Sopenharmony_ci return 0; 203262306a36Sopenharmony_ci 203362306a36Sopenharmony_ciout: 203462306a36Sopenharmony_ci kfree(ext); 203562306a36Sopenharmony_ci return err; 203662306a36Sopenharmony_ci} 203762306a36Sopenharmony_ci 203862306a36Sopenharmony_cistatic int 203962306a36Sopenharmony_ciptp_ocp_serial_line(struct ptp_ocp *bp, struct ocp_resource *r) 204062306a36Sopenharmony_ci{ 204162306a36Sopenharmony_ci struct pci_dev *pdev = bp->pdev; 204262306a36Sopenharmony_ci struct uart_8250_port uart; 204362306a36Sopenharmony_ci 204462306a36Sopenharmony_ci /* Setting UPF_IOREMAP and leaving port.membase unspecified lets 204562306a36Sopenharmony_ci * the serial port device claim and release the pci resource. 204662306a36Sopenharmony_ci */ 204762306a36Sopenharmony_ci memset(&uart, 0, sizeof(uart)); 204862306a36Sopenharmony_ci uart.port.dev = &pdev->dev; 204962306a36Sopenharmony_ci uart.port.iotype = UPIO_MEM; 205062306a36Sopenharmony_ci uart.port.regshift = 2; 205162306a36Sopenharmony_ci uart.port.mapbase = pci_resource_start(pdev, 0) + r->offset; 205262306a36Sopenharmony_ci uart.port.irq = pci_irq_vector(pdev, r->irq_vec); 205362306a36Sopenharmony_ci uart.port.uartclk = 50000000; 205462306a36Sopenharmony_ci uart.port.flags = UPF_FIXED_TYPE | UPF_IOREMAP | UPF_NO_THRE_TEST; 205562306a36Sopenharmony_ci uart.port.type = PORT_16550A; 205662306a36Sopenharmony_ci 205762306a36Sopenharmony_ci return serial8250_register_8250_port(&uart); 205862306a36Sopenharmony_ci} 205962306a36Sopenharmony_ci 206062306a36Sopenharmony_cistatic int 206162306a36Sopenharmony_ciptp_ocp_register_serial(struct ptp_ocp *bp, struct ocp_resource *r) 206262306a36Sopenharmony_ci{ 206362306a36Sopenharmony_ci struct ptp_ocp_serial_port *p = (struct ptp_ocp_serial_port *)r->extra; 206462306a36Sopenharmony_ci struct ptp_ocp_serial_port port = {}; 206562306a36Sopenharmony_ci 206662306a36Sopenharmony_ci port.line = ptp_ocp_serial_line(bp, r); 206762306a36Sopenharmony_ci if (port.line < 0) 206862306a36Sopenharmony_ci return port.line; 206962306a36Sopenharmony_ci 207062306a36Sopenharmony_ci if (p) 207162306a36Sopenharmony_ci port.baud = p->baud; 207262306a36Sopenharmony_ci 207362306a36Sopenharmony_ci bp_assign_entry(bp, r, port); 207462306a36Sopenharmony_ci 207562306a36Sopenharmony_ci return 0; 207662306a36Sopenharmony_ci} 207762306a36Sopenharmony_ci 207862306a36Sopenharmony_cistatic int 207962306a36Sopenharmony_ciptp_ocp_register_mem(struct ptp_ocp *bp, struct ocp_resource *r) 208062306a36Sopenharmony_ci{ 208162306a36Sopenharmony_ci void __iomem *mem; 208262306a36Sopenharmony_ci 208362306a36Sopenharmony_ci mem = ptp_ocp_get_mem(bp, r); 208462306a36Sopenharmony_ci if (IS_ERR(mem)) 208562306a36Sopenharmony_ci return PTR_ERR(mem); 208662306a36Sopenharmony_ci 208762306a36Sopenharmony_ci bp_assign_entry(bp, r, mem); 208862306a36Sopenharmony_ci 208962306a36Sopenharmony_ci return 0; 209062306a36Sopenharmony_ci} 209162306a36Sopenharmony_ci 209262306a36Sopenharmony_cistatic void 209362306a36Sopenharmony_ciptp_ocp_nmea_out_init(struct ptp_ocp *bp) 209462306a36Sopenharmony_ci{ 209562306a36Sopenharmony_ci if (!bp->nmea_out) 209662306a36Sopenharmony_ci return; 209762306a36Sopenharmony_ci 209862306a36Sopenharmony_ci iowrite32(0, &bp->nmea_out->ctrl); /* disable */ 209962306a36Sopenharmony_ci iowrite32(7, &bp->nmea_out->uart_baud); /* 115200 */ 210062306a36Sopenharmony_ci iowrite32(1, &bp->nmea_out->ctrl); /* enable */ 210162306a36Sopenharmony_ci} 210262306a36Sopenharmony_ci 210362306a36Sopenharmony_cistatic void 210462306a36Sopenharmony_ci_ptp_ocp_signal_init(struct ptp_ocp_signal *s, struct signal_reg __iomem *reg) 210562306a36Sopenharmony_ci{ 210662306a36Sopenharmony_ci u32 val; 210762306a36Sopenharmony_ci 210862306a36Sopenharmony_ci iowrite32(0, ®->enable); /* disable */ 210962306a36Sopenharmony_ci 211062306a36Sopenharmony_ci val = ioread32(®->polarity); 211162306a36Sopenharmony_ci s->polarity = val ? true : false; 211262306a36Sopenharmony_ci s->duty = 50; 211362306a36Sopenharmony_ci} 211462306a36Sopenharmony_ci 211562306a36Sopenharmony_cistatic void 211662306a36Sopenharmony_ciptp_ocp_signal_init(struct ptp_ocp *bp) 211762306a36Sopenharmony_ci{ 211862306a36Sopenharmony_ci int i; 211962306a36Sopenharmony_ci 212062306a36Sopenharmony_ci for (i = 0; i < 4; i++) 212162306a36Sopenharmony_ci if (bp->signal_out[i]) 212262306a36Sopenharmony_ci _ptp_ocp_signal_init(&bp->signal[i], 212362306a36Sopenharmony_ci bp->signal_out[i]->mem); 212462306a36Sopenharmony_ci} 212562306a36Sopenharmony_ci 212662306a36Sopenharmony_cistatic void 212762306a36Sopenharmony_ciptp_ocp_attr_group_del(struct ptp_ocp *bp) 212862306a36Sopenharmony_ci{ 212962306a36Sopenharmony_ci sysfs_remove_groups(&bp->dev.kobj, bp->attr_group); 213062306a36Sopenharmony_ci kfree(bp->attr_group); 213162306a36Sopenharmony_ci} 213262306a36Sopenharmony_ci 213362306a36Sopenharmony_cistatic int 213462306a36Sopenharmony_ciptp_ocp_attr_group_add(struct ptp_ocp *bp, 213562306a36Sopenharmony_ci const struct ocp_attr_group *attr_tbl) 213662306a36Sopenharmony_ci{ 213762306a36Sopenharmony_ci int count, i; 213862306a36Sopenharmony_ci int err; 213962306a36Sopenharmony_ci 214062306a36Sopenharmony_ci count = 0; 214162306a36Sopenharmony_ci for (i = 0; attr_tbl[i].cap; i++) 214262306a36Sopenharmony_ci if (attr_tbl[i].cap & bp->fw_cap) 214362306a36Sopenharmony_ci count++; 214462306a36Sopenharmony_ci 214562306a36Sopenharmony_ci bp->attr_group = kcalloc(count + 1, sizeof(struct attribute_group *), 214662306a36Sopenharmony_ci GFP_KERNEL); 214762306a36Sopenharmony_ci if (!bp->attr_group) 214862306a36Sopenharmony_ci return -ENOMEM; 214962306a36Sopenharmony_ci 215062306a36Sopenharmony_ci count = 0; 215162306a36Sopenharmony_ci for (i = 0; attr_tbl[i].cap; i++) 215262306a36Sopenharmony_ci if (attr_tbl[i].cap & bp->fw_cap) 215362306a36Sopenharmony_ci bp->attr_group[count++] = attr_tbl[i].group; 215462306a36Sopenharmony_ci 215562306a36Sopenharmony_ci err = sysfs_create_groups(&bp->dev.kobj, bp->attr_group); 215662306a36Sopenharmony_ci if (err) 215762306a36Sopenharmony_ci bp->attr_group[0] = NULL; 215862306a36Sopenharmony_ci 215962306a36Sopenharmony_ci return err; 216062306a36Sopenharmony_ci} 216162306a36Sopenharmony_ci 216262306a36Sopenharmony_cistatic void 216362306a36Sopenharmony_ciptp_ocp_enable_fpga(u32 __iomem *reg, u32 bit, bool enable) 216462306a36Sopenharmony_ci{ 216562306a36Sopenharmony_ci u32 ctrl; 216662306a36Sopenharmony_ci bool on; 216762306a36Sopenharmony_ci 216862306a36Sopenharmony_ci ctrl = ioread32(reg); 216962306a36Sopenharmony_ci on = ctrl & bit; 217062306a36Sopenharmony_ci if (on ^ enable) { 217162306a36Sopenharmony_ci ctrl &= ~bit; 217262306a36Sopenharmony_ci ctrl |= enable ? bit : 0; 217362306a36Sopenharmony_ci iowrite32(ctrl, reg); 217462306a36Sopenharmony_ci } 217562306a36Sopenharmony_ci} 217662306a36Sopenharmony_ci 217762306a36Sopenharmony_cistatic void 217862306a36Sopenharmony_ciptp_ocp_irig_out(struct ptp_ocp *bp, bool enable) 217962306a36Sopenharmony_ci{ 218062306a36Sopenharmony_ci return ptp_ocp_enable_fpga(&bp->irig_out->ctrl, 218162306a36Sopenharmony_ci IRIG_M_CTRL_ENABLE, enable); 218262306a36Sopenharmony_ci} 218362306a36Sopenharmony_ci 218462306a36Sopenharmony_cistatic void 218562306a36Sopenharmony_ciptp_ocp_irig_in(struct ptp_ocp *bp, bool enable) 218662306a36Sopenharmony_ci{ 218762306a36Sopenharmony_ci return ptp_ocp_enable_fpga(&bp->irig_in->ctrl, 218862306a36Sopenharmony_ci IRIG_S_CTRL_ENABLE, enable); 218962306a36Sopenharmony_ci} 219062306a36Sopenharmony_ci 219162306a36Sopenharmony_cistatic void 219262306a36Sopenharmony_ciptp_ocp_dcf_out(struct ptp_ocp *bp, bool enable) 219362306a36Sopenharmony_ci{ 219462306a36Sopenharmony_ci return ptp_ocp_enable_fpga(&bp->dcf_out->ctrl, 219562306a36Sopenharmony_ci DCF_M_CTRL_ENABLE, enable); 219662306a36Sopenharmony_ci} 219762306a36Sopenharmony_ci 219862306a36Sopenharmony_cistatic void 219962306a36Sopenharmony_ciptp_ocp_dcf_in(struct ptp_ocp *bp, bool enable) 220062306a36Sopenharmony_ci{ 220162306a36Sopenharmony_ci return ptp_ocp_enable_fpga(&bp->dcf_in->ctrl, 220262306a36Sopenharmony_ci DCF_S_CTRL_ENABLE, enable); 220362306a36Sopenharmony_ci} 220462306a36Sopenharmony_ci 220562306a36Sopenharmony_cistatic void 220662306a36Sopenharmony_ci__handle_signal_outputs(struct ptp_ocp *bp, u32 val) 220762306a36Sopenharmony_ci{ 220862306a36Sopenharmony_ci ptp_ocp_irig_out(bp, val & 0x00100010); 220962306a36Sopenharmony_ci ptp_ocp_dcf_out(bp, val & 0x00200020); 221062306a36Sopenharmony_ci} 221162306a36Sopenharmony_ci 221262306a36Sopenharmony_cistatic void 221362306a36Sopenharmony_ci__handle_signal_inputs(struct ptp_ocp *bp, u32 val) 221462306a36Sopenharmony_ci{ 221562306a36Sopenharmony_ci ptp_ocp_irig_in(bp, val & 0x00100010); 221662306a36Sopenharmony_ci ptp_ocp_dcf_in(bp, val & 0x00200020); 221762306a36Sopenharmony_ci} 221862306a36Sopenharmony_ci 221962306a36Sopenharmony_cistatic u32 222062306a36Sopenharmony_ciptp_ocp_sma_fb_get(struct ptp_ocp *bp, int sma_nr) 222162306a36Sopenharmony_ci{ 222262306a36Sopenharmony_ci u32 __iomem *gpio; 222362306a36Sopenharmony_ci u32 shift; 222462306a36Sopenharmony_ci 222562306a36Sopenharmony_ci if (bp->sma[sma_nr - 1].fixed_fcn) 222662306a36Sopenharmony_ci return (sma_nr - 1) & 1; 222762306a36Sopenharmony_ci 222862306a36Sopenharmony_ci if (bp->sma[sma_nr - 1].mode == SMA_MODE_IN) 222962306a36Sopenharmony_ci gpio = sma_nr > 2 ? &bp->sma_map2->gpio1 : &bp->sma_map1->gpio1; 223062306a36Sopenharmony_ci else 223162306a36Sopenharmony_ci gpio = sma_nr > 2 ? &bp->sma_map1->gpio2 : &bp->sma_map2->gpio2; 223262306a36Sopenharmony_ci shift = sma_nr & 1 ? 0 : 16; 223362306a36Sopenharmony_ci 223462306a36Sopenharmony_ci return (ioread32(gpio) >> shift) & 0xffff; 223562306a36Sopenharmony_ci} 223662306a36Sopenharmony_ci 223762306a36Sopenharmony_cistatic int 223862306a36Sopenharmony_ciptp_ocp_sma_fb_set_output(struct ptp_ocp *bp, int sma_nr, u32 val) 223962306a36Sopenharmony_ci{ 224062306a36Sopenharmony_ci u32 reg, mask, shift; 224162306a36Sopenharmony_ci unsigned long flags; 224262306a36Sopenharmony_ci u32 __iomem *gpio; 224362306a36Sopenharmony_ci 224462306a36Sopenharmony_ci gpio = sma_nr > 2 ? &bp->sma_map1->gpio2 : &bp->sma_map2->gpio2; 224562306a36Sopenharmony_ci shift = sma_nr & 1 ? 0 : 16; 224662306a36Sopenharmony_ci 224762306a36Sopenharmony_ci mask = 0xffff << (16 - shift); 224862306a36Sopenharmony_ci 224962306a36Sopenharmony_ci spin_lock_irqsave(&bp->lock, flags); 225062306a36Sopenharmony_ci 225162306a36Sopenharmony_ci reg = ioread32(gpio); 225262306a36Sopenharmony_ci reg = (reg & mask) | (val << shift); 225362306a36Sopenharmony_ci 225462306a36Sopenharmony_ci __handle_signal_outputs(bp, reg); 225562306a36Sopenharmony_ci 225662306a36Sopenharmony_ci iowrite32(reg, gpio); 225762306a36Sopenharmony_ci 225862306a36Sopenharmony_ci spin_unlock_irqrestore(&bp->lock, flags); 225962306a36Sopenharmony_ci 226062306a36Sopenharmony_ci return 0; 226162306a36Sopenharmony_ci} 226262306a36Sopenharmony_ci 226362306a36Sopenharmony_cistatic int 226462306a36Sopenharmony_ciptp_ocp_sma_fb_set_inputs(struct ptp_ocp *bp, int sma_nr, u32 val) 226562306a36Sopenharmony_ci{ 226662306a36Sopenharmony_ci u32 reg, mask, shift; 226762306a36Sopenharmony_ci unsigned long flags; 226862306a36Sopenharmony_ci u32 __iomem *gpio; 226962306a36Sopenharmony_ci 227062306a36Sopenharmony_ci gpio = sma_nr > 2 ? &bp->sma_map2->gpio1 : &bp->sma_map1->gpio1; 227162306a36Sopenharmony_ci shift = sma_nr & 1 ? 0 : 16; 227262306a36Sopenharmony_ci 227362306a36Sopenharmony_ci mask = 0xffff << (16 - shift); 227462306a36Sopenharmony_ci 227562306a36Sopenharmony_ci spin_lock_irqsave(&bp->lock, flags); 227662306a36Sopenharmony_ci 227762306a36Sopenharmony_ci reg = ioread32(gpio); 227862306a36Sopenharmony_ci reg = (reg & mask) | (val << shift); 227962306a36Sopenharmony_ci 228062306a36Sopenharmony_ci __handle_signal_inputs(bp, reg); 228162306a36Sopenharmony_ci 228262306a36Sopenharmony_ci iowrite32(reg, gpio); 228362306a36Sopenharmony_ci 228462306a36Sopenharmony_ci spin_unlock_irqrestore(&bp->lock, flags); 228562306a36Sopenharmony_ci 228662306a36Sopenharmony_ci return 0; 228762306a36Sopenharmony_ci} 228862306a36Sopenharmony_ci 228962306a36Sopenharmony_cistatic void 229062306a36Sopenharmony_ciptp_ocp_sma_fb_init(struct ptp_ocp *bp) 229162306a36Sopenharmony_ci{ 229262306a36Sopenharmony_ci u32 reg; 229362306a36Sopenharmony_ci int i; 229462306a36Sopenharmony_ci 229562306a36Sopenharmony_ci /* defaults */ 229662306a36Sopenharmony_ci bp->sma[0].mode = SMA_MODE_IN; 229762306a36Sopenharmony_ci bp->sma[1].mode = SMA_MODE_IN; 229862306a36Sopenharmony_ci bp->sma[2].mode = SMA_MODE_OUT; 229962306a36Sopenharmony_ci bp->sma[3].mode = SMA_MODE_OUT; 230062306a36Sopenharmony_ci for (i = 0; i < 4; i++) 230162306a36Sopenharmony_ci bp->sma[i].default_fcn = i & 1; 230262306a36Sopenharmony_ci 230362306a36Sopenharmony_ci /* If no SMA1 map, the pin functions and directions are fixed. */ 230462306a36Sopenharmony_ci if (!bp->sma_map1) { 230562306a36Sopenharmony_ci for (i = 0; i < 4; i++) { 230662306a36Sopenharmony_ci bp->sma[i].fixed_fcn = true; 230762306a36Sopenharmony_ci bp->sma[i].fixed_dir = true; 230862306a36Sopenharmony_ci } 230962306a36Sopenharmony_ci return; 231062306a36Sopenharmony_ci } 231162306a36Sopenharmony_ci 231262306a36Sopenharmony_ci /* If SMA2 GPIO output map is all 1, it is not present. 231362306a36Sopenharmony_ci * This indicates the firmware has fixed direction SMA pins. 231462306a36Sopenharmony_ci */ 231562306a36Sopenharmony_ci reg = ioread32(&bp->sma_map2->gpio2); 231662306a36Sopenharmony_ci if (reg == 0xffffffff) { 231762306a36Sopenharmony_ci for (i = 0; i < 4; i++) 231862306a36Sopenharmony_ci bp->sma[i].fixed_dir = true; 231962306a36Sopenharmony_ci } else { 232062306a36Sopenharmony_ci reg = ioread32(&bp->sma_map1->gpio1); 232162306a36Sopenharmony_ci bp->sma[0].mode = reg & BIT(15) ? SMA_MODE_IN : SMA_MODE_OUT; 232262306a36Sopenharmony_ci bp->sma[1].mode = reg & BIT(31) ? SMA_MODE_IN : SMA_MODE_OUT; 232362306a36Sopenharmony_ci 232462306a36Sopenharmony_ci reg = ioread32(&bp->sma_map1->gpio2); 232562306a36Sopenharmony_ci bp->sma[2].mode = reg & BIT(15) ? SMA_MODE_OUT : SMA_MODE_IN; 232662306a36Sopenharmony_ci bp->sma[3].mode = reg & BIT(31) ? SMA_MODE_OUT : SMA_MODE_IN; 232762306a36Sopenharmony_ci } 232862306a36Sopenharmony_ci} 232962306a36Sopenharmony_ci 233062306a36Sopenharmony_cistatic const struct ocp_sma_op ocp_fb_sma_op = { 233162306a36Sopenharmony_ci .tbl = { ptp_ocp_sma_in, ptp_ocp_sma_out }, 233262306a36Sopenharmony_ci .init = ptp_ocp_sma_fb_init, 233362306a36Sopenharmony_ci .get = ptp_ocp_sma_fb_get, 233462306a36Sopenharmony_ci .set_inputs = ptp_ocp_sma_fb_set_inputs, 233562306a36Sopenharmony_ci .set_output = ptp_ocp_sma_fb_set_output, 233662306a36Sopenharmony_ci}; 233762306a36Sopenharmony_ci 233862306a36Sopenharmony_cistatic int 233962306a36Sopenharmony_ciptp_ocp_fb_set_pins(struct ptp_ocp *bp) 234062306a36Sopenharmony_ci{ 234162306a36Sopenharmony_ci struct ptp_pin_desc *config; 234262306a36Sopenharmony_ci int i; 234362306a36Sopenharmony_ci 234462306a36Sopenharmony_ci config = kcalloc(4, sizeof(*config), GFP_KERNEL); 234562306a36Sopenharmony_ci if (!config) 234662306a36Sopenharmony_ci return -ENOMEM; 234762306a36Sopenharmony_ci 234862306a36Sopenharmony_ci for (i = 0; i < 4; i++) { 234962306a36Sopenharmony_ci sprintf(config[i].name, "sma%d", i + 1); 235062306a36Sopenharmony_ci config[i].index = i; 235162306a36Sopenharmony_ci } 235262306a36Sopenharmony_ci 235362306a36Sopenharmony_ci bp->ptp_info.n_pins = 4; 235462306a36Sopenharmony_ci bp->ptp_info.pin_config = config; 235562306a36Sopenharmony_ci 235662306a36Sopenharmony_ci return 0; 235762306a36Sopenharmony_ci} 235862306a36Sopenharmony_ci 235962306a36Sopenharmony_cistatic void 236062306a36Sopenharmony_ciptp_ocp_fb_set_version(struct ptp_ocp *bp) 236162306a36Sopenharmony_ci{ 236262306a36Sopenharmony_ci u64 cap = OCP_CAP_BASIC; 236362306a36Sopenharmony_ci u32 version; 236462306a36Sopenharmony_ci 236562306a36Sopenharmony_ci version = ioread32(&bp->image->version); 236662306a36Sopenharmony_ci 236762306a36Sopenharmony_ci /* if lower 16 bits are empty, this is the fw loader. */ 236862306a36Sopenharmony_ci if ((version & 0xffff) == 0) { 236962306a36Sopenharmony_ci version = version >> 16; 237062306a36Sopenharmony_ci bp->fw_loader = true; 237162306a36Sopenharmony_ci } 237262306a36Sopenharmony_ci 237362306a36Sopenharmony_ci bp->fw_tag = version >> 15; 237462306a36Sopenharmony_ci bp->fw_version = version & 0x7fff; 237562306a36Sopenharmony_ci 237662306a36Sopenharmony_ci if (bp->fw_tag) { 237762306a36Sopenharmony_ci /* FPGA firmware */ 237862306a36Sopenharmony_ci if (version >= 5) 237962306a36Sopenharmony_ci cap |= OCP_CAP_SIGNAL | OCP_CAP_FREQ; 238062306a36Sopenharmony_ci } else { 238162306a36Sopenharmony_ci /* SOM firmware */ 238262306a36Sopenharmony_ci if (version >= 19) 238362306a36Sopenharmony_ci cap |= OCP_CAP_SIGNAL; 238462306a36Sopenharmony_ci if (version >= 20) 238562306a36Sopenharmony_ci cap |= OCP_CAP_FREQ; 238662306a36Sopenharmony_ci } 238762306a36Sopenharmony_ci 238862306a36Sopenharmony_ci bp->fw_cap = cap; 238962306a36Sopenharmony_ci} 239062306a36Sopenharmony_ci 239162306a36Sopenharmony_ci/* FB specific board initializers; last "resource" registered. */ 239262306a36Sopenharmony_cistatic int 239362306a36Sopenharmony_ciptp_ocp_fb_board_init(struct ptp_ocp *bp, struct ocp_resource *r) 239462306a36Sopenharmony_ci{ 239562306a36Sopenharmony_ci int err; 239662306a36Sopenharmony_ci 239762306a36Sopenharmony_ci bp->flash_start = 1024 * 4096; 239862306a36Sopenharmony_ci bp->eeprom_map = fb_eeprom_map; 239962306a36Sopenharmony_ci bp->fw_version = ioread32(&bp->image->version); 240062306a36Sopenharmony_ci bp->sma_op = &ocp_fb_sma_op; 240162306a36Sopenharmony_ci 240262306a36Sopenharmony_ci ptp_ocp_fb_set_version(bp); 240362306a36Sopenharmony_ci 240462306a36Sopenharmony_ci ptp_ocp_tod_init(bp); 240562306a36Sopenharmony_ci ptp_ocp_nmea_out_init(bp); 240662306a36Sopenharmony_ci ptp_ocp_sma_init(bp); 240762306a36Sopenharmony_ci ptp_ocp_signal_init(bp); 240862306a36Sopenharmony_ci 240962306a36Sopenharmony_ci err = ptp_ocp_attr_group_add(bp, fb_timecard_groups); 241062306a36Sopenharmony_ci if (err) 241162306a36Sopenharmony_ci return err; 241262306a36Sopenharmony_ci 241362306a36Sopenharmony_ci err = ptp_ocp_fb_set_pins(bp); 241462306a36Sopenharmony_ci if (err) 241562306a36Sopenharmony_ci return err; 241662306a36Sopenharmony_ci 241762306a36Sopenharmony_ci return ptp_ocp_init_clock(bp); 241862306a36Sopenharmony_ci} 241962306a36Sopenharmony_ci 242062306a36Sopenharmony_cistatic bool 242162306a36Sopenharmony_ciptp_ocp_allow_irq(struct ptp_ocp *bp, struct ocp_resource *r) 242262306a36Sopenharmony_ci{ 242362306a36Sopenharmony_ci bool allow = !r->irq_vec || r->irq_vec < bp->n_irqs; 242462306a36Sopenharmony_ci 242562306a36Sopenharmony_ci if (!allow) 242662306a36Sopenharmony_ci dev_err(&bp->pdev->dev, "irq %d out of range, skipping %s\n", 242762306a36Sopenharmony_ci r->irq_vec, r->name); 242862306a36Sopenharmony_ci return allow; 242962306a36Sopenharmony_ci} 243062306a36Sopenharmony_ci 243162306a36Sopenharmony_cistatic int 243262306a36Sopenharmony_ciptp_ocp_register_resources(struct ptp_ocp *bp, kernel_ulong_t driver_data) 243362306a36Sopenharmony_ci{ 243462306a36Sopenharmony_ci struct ocp_resource *r, *table; 243562306a36Sopenharmony_ci int err = 0; 243662306a36Sopenharmony_ci 243762306a36Sopenharmony_ci table = (struct ocp_resource *)driver_data; 243862306a36Sopenharmony_ci for (r = table; r->setup; r++) { 243962306a36Sopenharmony_ci if (!ptp_ocp_allow_irq(bp, r)) 244062306a36Sopenharmony_ci continue; 244162306a36Sopenharmony_ci err = r->setup(bp, r); 244262306a36Sopenharmony_ci if (err) { 244362306a36Sopenharmony_ci dev_err(&bp->pdev->dev, 244462306a36Sopenharmony_ci "Could not register %s: err %d\n", 244562306a36Sopenharmony_ci r->name, err); 244662306a36Sopenharmony_ci break; 244762306a36Sopenharmony_ci } 244862306a36Sopenharmony_ci } 244962306a36Sopenharmony_ci return err; 245062306a36Sopenharmony_ci} 245162306a36Sopenharmony_ci 245262306a36Sopenharmony_cistatic void 245362306a36Sopenharmony_ciptp_ocp_art_sma_init(struct ptp_ocp *bp) 245462306a36Sopenharmony_ci{ 245562306a36Sopenharmony_ci u32 reg; 245662306a36Sopenharmony_ci int i; 245762306a36Sopenharmony_ci 245862306a36Sopenharmony_ci /* defaults */ 245962306a36Sopenharmony_ci bp->sma[0].mode = SMA_MODE_IN; 246062306a36Sopenharmony_ci bp->sma[1].mode = SMA_MODE_IN; 246162306a36Sopenharmony_ci bp->sma[2].mode = SMA_MODE_OUT; 246262306a36Sopenharmony_ci bp->sma[3].mode = SMA_MODE_OUT; 246362306a36Sopenharmony_ci 246462306a36Sopenharmony_ci bp->sma[0].default_fcn = 0x08; /* IN: 10Mhz */ 246562306a36Sopenharmony_ci bp->sma[1].default_fcn = 0x01; /* IN: PPS1 */ 246662306a36Sopenharmony_ci bp->sma[2].default_fcn = 0x10; /* OUT: 10Mhz */ 246762306a36Sopenharmony_ci bp->sma[3].default_fcn = 0x02; /* OUT: PHC */ 246862306a36Sopenharmony_ci 246962306a36Sopenharmony_ci /* If no SMA map, the pin functions and directions are fixed. */ 247062306a36Sopenharmony_ci if (!bp->art_sma) { 247162306a36Sopenharmony_ci for (i = 0; i < 4; i++) { 247262306a36Sopenharmony_ci bp->sma[i].fixed_fcn = true; 247362306a36Sopenharmony_ci bp->sma[i].fixed_dir = true; 247462306a36Sopenharmony_ci } 247562306a36Sopenharmony_ci return; 247662306a36Sopenharmony_ci } 247762306a36Sopenharmony_ci 247862306a36Sopenharmony_ci for (i = 0; i < 4; i++) { 247962306a36Sopenharmony_ci reg = ioread32(&bp->art_sma->map[i].gpio); 248062306a36Sopenharmony_ci 248162306a36Sopenharmony_ci switch (reg & 0xff) { 248262306a36Sopenharmony_ci case 0: 248362306a36Sopenharmony_ci bp->sma[i].fixed_fcn = true; 248462306a36Sopenharmony_ci bp->sma[i].fixed_dir = true; 248562306a36Sopenharmony_ci break; 248662306a36Sopenharmony_ci case 1: 248762306a36Sopenharmony_ci case 8: 248862306a36Sopenharmony_ci bp->sma[i].mode = SMA_MODE_IN; 248962306a36Sopenharmony_ci break; 249062306a36Sopenharmony_ci default: 249162306a36Sopenharmony_ci bp->sma[i].mode = SMA_MODE_OUT; 249262306a36Sopenharmony_ci break; 249362306a36Sopenharmony_ci } 249462306a36Sopenharmony_ci } 249562306a36Sopenharmony_ci} 249662306a36Sopenharmony_ci 249762306a36Sopenharmony_cistatic u32 249862306a36Sopenharmony_ciptp_ocp_art_sma_get(struct ptp_ocp *bp, int sma_nr) 249962306a36Sopenharmony_ci{ 250062306a36Sopenharmony_ci if (bp->sma[sma_nr - 1].fixed_fcn) 250162306a36Sopenharmony_ci return bp->sma[sma_nr - 1].default_fcn; 250262306a36Sopenharmony_ci 250362306a36Sopenharmony_ci return ioread32(&bp->art_sma->map[sma_nr - 1].gpio) & 0xff; 250462306a36Sopenharmony_ci} 250562306a36Sopenharmony_ci 250662306a36Sopenharmony_ci/* note: store 0 is considered invalid. */ 250762306a36Sopenharmony_cistatic int 250862306a36Sopenharmony_ciptp_ocp_art_sma_set(struct ptp_ocp *bp, int sma_nr, u32 val) 250962306a36Sopenharmony_ci{ 251062306a36Sopenharmony_ci unsigned long flags; 251162306a36Sopenharmony_ci u32 __iomem *gpio; 251262306a36Sopenharmony_ci int err = 0; 251362306a36Sopenharmony_ci u32 reg; 251462306a36Sopenharmony_ci 251562306a36Sopenharmony_ci val &= SMA_SELECT_MASK; 251662306a36Sopenharmony_ci if (hweight32(val) > 1) 251762306a36Sopenharmony_ci return -EINVAL; 251862306a36Sopenharmony_ci 251962306a36Sopenharmony_ci gpio = &bp->art_sma->map[sma_nr - 1].gpio; 252062306a36Sopenharmony_ci 252162306a36Sopenharmony_ci spin_lock_irqsave(&bp->lock, flags); 252262306a36Sopenharmony_ci reg = ioread32(gpio); 252362306a36Sopenharmony_ci if (((reg >> 16) & val) == 0) { 252462306a36Sopenharmony_ci err = -EOPNOTSUPP; 252562306a36Sopenharmony_ci } else { 252662306a36Sopenharmony_ci reg = (reg & 0xff00) | (val & 0xff); 252762306a36Sopenharmony_ci iowrite32(reg, gpio); 252862306a36Sopenharmony_ci } 252962306a36Sopenharmony_ci spin_unlock_irqrestore(&bp->lock, flags); 253062306a36Sopenharmony_ci 253162306a36Sopenharmony_ci return err; 253262306a36Sopenharmony_ci} 253362306a36Sopenharmony_ci 253462306a36Sopenharmony_cistatic const struct ocp_sma_op ocp_art_sma_op = { 253562306a36Sopenharmony_ci .tbl = { ptp_ocp_art_sma_in, ptp_ocp_art_sma_out }, 253662306a36Sopenharmony_ci .init = ptp_ocp_art_sma_init, 253762306a36Sopenharmony_ci .get = ptp_ocp_art_sma_get, 253862306a36Sopenharmony_ci .set_inputs = ptp_ocp_art_sma_set, 253962306a36Sopenharmony_ci .set_output = ptp_ocp_art_sma_set, 254062306a36Sopenharmony_ci}; 254162306a36Sopenharmony_ci 254262306a36Sopenharmony_ci/* ART specific board initializers; last "resource" registered. */ 254362306a36Sopenharmony_cistatic int 254462306a36Sopenharmony_ciptp_ocp_art_board_init(struct ptp_ocp *bp, struct ocp_resource *r) 254562306a36Sopenharmony_ci{ 254662306a36Sopenharmony_ci int err; 254762306a36Sopenharmony_ci 254862306a36Sopenharmony_ci bp->flash_start = 0x1000000; 254962306a36Sopenharmony_ci bp->eeprom_map = art_eeprom_map; 255062306a36Sopenharmony_ci bp->fw_cap = OCP_CAP_BASIC; 255162306a36Sopenharmony_ci bp->fw_version = ioread32(&bp->reg->version); 255262306a36Sopenharmony_ci bp->fw_tag = 2; 255362306a36Sopenharmony_ci bp->sma_op = &ocp_art_sma_op; 255462306a36Sopenharmony_ci 255562306a36Sopenharmony_ci /* Enable MAC serial port during initialisation */ 255662306a36Sopenharmony_ci iowrite32(1, &bp->board_config->mro50_serial_activate); 255762306a36Sopenharmony_ci 255862306a36Sopenharmony_ci ptp_ocp_sma_init(bp); 255962306a36Sopenharmony_ci 256062306a36Sopenharmony_ci err = ptp_ocp_attr_group_add(bp, art_timecard_groups); 256162306a36Sopenharmony_ci if (err) 256262306a36Sopenharmony_ci return err; 256362306a36Sopenharmony_ci 256462306a36Sopenharmony_ci return ptp_ocp_init_clock(bp); 256562306a36Sopenharmony_ci} 256662306a36Sopenharmony_ci 256762306a36Sopenharmony_cistatic ssize_t 256862306a36Sopenharmony_ciptp_ocp_show_output(const struct ocp_selector *tbl, u32 val, char *buf, 256962306a36Sopenharmony_ci int def_val) 257062306a36Sopenharmony_ci{ 257162306a36Sopenharmony_ci const char *name; 257262306a36Sopenharmony_ci ssize_t count; 257362306a36Sopenharmony_ci 257462306a36Sopenharmony_ci count = sysfs_emit(buf, "OUT: "); 257562306a36Sopenharmony_ci name = ptp_ocp_select_name_from_val(tbl, val); 257662306a36Sopenharmony_ci if (!name) 257762306a36Sopenharmony_ci name = ptp_ocp_select_name_from_val(tbl, def_val); 257862306a36Sopenharmony_ci count += sysfs_emit_at(buf, count, "%s\n", name); 257962306a36Sopenharmony_ci return count; 258062306a36Sopenharmony_ci} 258162306a36Sopenharmony_ci 258262306a36Sopenharmony_cistatic ssize_t 258362306a36Sopenharmony_ciptp_ocp_show_inputs(const struct ocp_selector *tbl, u32 val, char *buf, 258462306a36Sopenharmony_ci int def_val) 258562306a36Sopenharmony_ci{ 258662306a36Sopenharmony_ci const char *name; 258762306a36Sopenharmony_ci ssize_t count; 258862306a36Sopenharmony_ci int i; 258962306a36Sopenharmony_ci 259062306a36Sopenharmony_ci count = sysfs_emit(buf, "IN: "); 259162306a36Sopenharmony_ci for (i = 0; tbl[i].name; i++) { 259262306a36Sopenharmony_ci if (val & tbl[i].value) { 259362306a36Sopenharmony_ci name = tbl[i].name; 259462306a36Sopenharmony_ci count += sysfs_emit_at(buf, count, "%s ", name); 259562306a36Sopenharmony_ci } 259662306a36Sopenharmony_ci } 259762306a36Sopenharmony_ci if (!val && def_val >= 0) { 259862306a36Sopenharmony_ci name = ptp_ocp_select_name_from_val(tbl, def_val); 259962306a36Sopenharmony_ci count += sysfs_emit_at(buf, count, "%s ", name); 260062306a36Sopenharmony_ci } 260162306a36Sopenharmony_ci if (count) 260262306a36Sopenharmony_ci count--; 260362306a36Sopenharmony_ci count += sysfs_emit_at(buf, count, "\n"); 260462306a36Sopenharmony_ci return count; 260562306a36Sopenharmony_ci} 260662306a36Sopenharmony_ci 260762306a36Sopenharmony_cistatic int 260862306a36Sopenharmony_cisma_parse_inputs(const struct ocp_selector * const tbl[], const char *buf, 260962306a36Sopenharmony_ci enum ptp_ocp_sma_mode *mode) 261062306a36Sopenharmony_ci{ 261162306a36Sopenharmony_ci int idx, count, dir; 261262306a36Sopenharmony_ci char **argv; 261362306a36Sopenharmony_ci int ret; 261462306a36Sopenharmony_ci 261562306a36Sopenharmony_ci argv = argv_split(GFP_KERNEL, buf, &count); 261662306a36Sopenharmony_ci if (!argv) 261762306a36Sopenharmony_ci return -ENOMEM; 261862306a36Sopenharmony_ci 261962306a36Sopenharmony_ci ret = -EINVAL; 262062306a36Sopenharmony_ci if (!count) 262162306a36Sopenharmony_ci goto out; 262262306a36Sopenharmony_ci 262362306a36Sopenharmony_ci idx = 0; 262462306a36Sopenharmony_ci dir = *mode == SMA_MODE_IN ? 0 : 1; 262562306a36Sopenharmony_ci if (!strcasecmp("IN:", argv[0])) { 262662306a36Sopenharmony_ci dir = 0; 262762306a36Sopenharmony_ci idx++; 262862306a36Sopenharmony_ci } 262962306a36Sopenharmony_ci if (!strcasecmp("OUT:", argv[0])) { 263062306a36Sopenharmony_ci dir = 1; 263162306a36Sopenharmony_ci idx++; 263262306a36Sopenharmony_ci } 263362306a36Sopenharmony_ci *mode = dir == 0 ? SMA_MODE_IN : SMA_MODE_OUT; 263462306a36Sopenharmony_ci 263562306a36Sopenharmony_ci ret = 0; 263662306a36Sopenharmony_ci for (; idx < count; idx++) 263762306a36Sopenharmony_ci ret |= ptp_ocp_select_val_from_name(tbl[dir], argv[idx]); 263862306a36Sopenharmony_ci if (ret < 0) 263962306a36Sopenharmony_ci ret = -EINVAL; 264062306a36Sopenharmony_ci 264162306a36Sopenharmony_ciout: 264262306a36Sopenharmony_ci argv_free(argv); 264362306a36Sopenharmony_ci return ret; 264462306a36Sopenharmony_ci} 264562306a36Sopenharmony_ci 264662306a36Sopenharmony_cistatic ssize_t 264762306a36Sopenharmony_ciptp_ocp_sma_show(struct ptp_ocp *bp, int sma_nr, char *buf, 264862306a36Sopenharmony_ci int default_in_val, int default_out_val) 264962306a36Sopenharmony_ci{ 265062306a36Sopenharmony_ci struct ptp_ocp_sma_connector *sma = &bp->sma[sma_nr - 1]; 265162306a36Sopenharmony_ci const struct ocp_selector * const *tbl; 265262306a36Sopenharmony_ci u32 val; 265362306a36Sopenharmony_ci 265462306a36Sopenharmony_ci tbl = bp->sma_op->tbl; 265562306a36Sopenharmony_ci val = ptp_ocp_sma_get(bp, sma_nr) & SMA_SELECT_MASK; 265662306a36Sopenharmony_ci 265762306a36Sopenharmony_ci if (sma->mode == SMA_MODE_IN) { 265862306a36Sopenharmony_ci if (sma->disabled) 265962306a36Sopenharmony_ci val = SMA_DISABLE; 266062306a36Sopenharmony_ci return ptp_ocp_show_inputs(tbl[0], val, buf, default_in_val); 266162306a36Sopenharmony_ci } 266262306a36Sopenharmony_ci 266362306a36Sopenharmony_ci return ptp_ocp_show_output(tbl[1], val, buf, default_out_val); 266462306a36Sopenharmony_ci} 266562306a36Sopenharmony_ci 266662306a36Sopenharmony_cistatic ssize_t 266762306a36Sopenharmony_cisma1_show(struct device *dev, struct device_attribute *attr, char *buf) 266862306a36Sopenharmony_ci{ 266962306a36Sopenharmony_ci struct ptp_ocp *bp = dev_get_drvdata(dev); 267062306a36Sopenharmony_ci 267162306a36Sopenharmony_ci return ptp_ocp_sma_show(bp, 1, buf, 0, 1); 267262306a36Sopenharmony_ci} 267362306a36Sopenharmony_ci 267462306a36Sopenharmony_cistatic ssize_t 267562306a36Sopenharmony_cisma2_show(struct device *dev, struct device_attribute *attr, char *buf) 267662306a36Sopenharmony_ci{ 267762306a36Sopenharmony_ci struct ptp_ocp *bp = dev_get_drvdata(dev); 267862306a36Sopenharmony_ci 267962306a36Sopenharmony_ci return ptp_ocp_sma_show(bp, 2, buf, -1, 1); 268062306a36Sopenharmony_ci} 268162306a36Sopenharmony_ci 268262306a36Sopenharmony_cistatic ssize_t 268362306a36Sopenharmony_cisma3_show(struct device *dev, struct device_attribute *attr, char *buf) 268462306a36Sopenharmony_ci{ 268562306a36Sopenharmony_ci struct ptp_ocp *bp = dev_get_drvdata(dev); 268662306a36Sopenharmony_ci 268762306a36Sopenharmony_ci return ptp_ocp_sma_show(bp, 3, buf, -1, 0); 268862306a36Sopenharmony_ci} 268962306a36Sopenharmony_ci 269062306a36Sopenharmony_cistatic ssize_t 269162306a36Sopenharmony_cisma4_show(struct device *dev, struct device_attribute *attr, char *buf) 269262306a36Sopenharmony_ci{ 269362306a36Sopenharmony_ci struct ptp_ocp *bp = dev_get_drvdata(dev); 269462306a36Sopenharmony_ci 269562306a36Sopenharmony_ci return ptp_ocp_sma_show(bp, 4, buf, -1, 1); 269662306a36Sopenharmony_ci} 269762306a36Sopenharmony_ci 269862306a36Sopenharmony_cistatic int 269962306a36Sopenharmony_ciptp_ocp_sma_store(struct ptp_ocp *bp, const char *buf, int sma_nr) 270062306a36Sopenharmony_ci{ 270162306a36Sopenharmony_ci struct ptp_ocp_sma_connector *sma = &bp->sma[sma_nr - 1]; 270262306a36Sopenharmony_ci enum ptp_ocp_sma_mode mode; 270362306a36Sopenharmony_ci int val; 270462306a36Sopenharmony_ci 270562306a36Sopenharmony_ci mode = sma->mode; 270662306a36Sopenharmony_ci val = sma_parse_inputs(bp->sma_op->tbl, buf, &mode); 270762306a36Sopenharmony_ci if (val < 0) 270862306a36Sopenharmony_ci return val; 270962306a36Sopenharmony_ci 271062306a36Sopenharmony_ci if (sma->fixed_dir && (mode != sma->mode || val & SMA_DISABLE)) 271162306a36Sopenharmony_ci return -EOPNOTSUPP; 271262306a36Sopenharmony_ci 271362306a36Sopenharmony_ci if (sma->fixed_fcn) { 271462306a36Sopenharmony_ci if (val != sma->default_fcn) 271562306a36Sopenharmony_ci return -EOPNOTSUPP; 271662306a36Sopenharmony_ci return 0; 271762306a36Sopenharmony_ci } 271862306a36Sopenharmony_ci 271962306a36Sopenharmony_ci sma->disabled = !!(val & SMA_DISABLE); 272062306a36Sopenharmony_ci 272162306a36Sopenharmony_ci if (mode != sma->mode) { 272262306a36Sopenharmony_ci if (mode == SMA_MODE_IN) 272362306a36Sopenharmony_ci ptp_ocp_sma_set_output(bp, sma_nr, 0); 272462306a36Sopenharmony_ci else 272562306a36Sopenharmony_ci ptp_ocp_sma_set_inputs(bp, sma_nr, 0); 272662306a36Sopenharmony_ci sma->mode = mode; 272762306a36Sopenharmony_ci } 272862306a36Sopenharmony_ci 272962306a36Sopenharmony_ci if (!sma->fixed_dir) 273062306a36Sopenharmony_ci val |= SMA_ENABLE; /* add enable bit */ 273162306a36Sopenharmony_ci 273262306a36Sopenharmony_ci if (sma->disabled) 273362306a36Sopenharmony_ci val = 0; 273462306a36Sopenharmony_ci 273562306a36Sopenharmony_ci if (mode == SMA_MODE_IN) 273662306a36Sopenharmony_ci val = ptp_ocp_sma_set_inputs(bp, sma_nr, val); 273762306a36Sopenharmony_ci else 273862306a36Sopenharmony_ci val = ptp_ocp_sma_set_output(bp, sma_nr, val); 273962306a36Sopenharmony_ci 274062306a36Sopenharmony_ci return val; 274162306a36Sopenharmony_ci} 274262306a36Sopenharmony_ci 274362306a36Sopenharmony_cistatic ssize_t 274462306a36Sopenharmony_cisma1_store(struct device *dev, struct device_attribute *attr, 274562306a36Sopenharmony_ci const char *buf, size_t count) 274662306a36Sopenharmony_ci{ 274762306a36Sopenharmony_ci struct ptp_ocp *bp = dev_get_drvdata(dev); 274862306a36Sopenharmony_ci int err; 274962306a36Sopenharmony_ci 275062306a36Sopenharmony_ci err = ptp_ocp_sma_store(bp, buf, 1); 275162306a36Sopenharmony_ci return err ? err : count; 275262306a36Sopenharmony_ci} 275362306a36Sopenharmony_ci 275462306a36Sopenharmony_cistatic ssize_t 275562306a36Sopenharmony_cisma2_store(struct device *dev, struct device_attribute *attr, 275662306a36Sopenharmony_ci const char *buf, size_t count) 275762306a36Sopenharmony_ci{ 275862306a36Sopenharmony_ci struct ptp_ocp *bp = dev_get_drvdata(dev); 275962306a36Sopenharmony_ci int err; 276062306a36Sopenharmony_ci 276162306a36Sopenharmony_ci err = ptp_ocp_sma_store(bp, buf, 2); 276262306a36Sopenharmony_ci return err ? err : count; 276362306a36Sopenharmony_ci} 276462306a36Sopenharmony_ci 276562306a36Sopenharmony_cistatic ssize_t 276662306a36Sopenharmony_cisma3_store(struct device *dev, struct device_attribute *attr, 276762306a36Sopenharmony_ci const char *buf, size_t count) 276862306a36Sopenharmony_ci{ 276962306a36Sopenharmony_ci struct ptp_ocp *bp = dev_get_drvdata(dev); 277062306a36Sopenharmony_ci int err; 277162306a36Sopenharmony_ci 277262306a36Sopenharmony_ci err = ptp_ocp_sma_store(bp, buf, 3); 277362306a36Sopenharmony_ci return err ? err : count; 277462306a36Sopenharmony_ci} 277562306a36Sopenharmony_ci 277662306a36Sopenharmony_cistatic ssize_t 277762306a36Sopenharmony_cisma4_store(struct device *dev, struct device_attribute *attr, 277862306a36Sopenharmony_ci const char *buf, size_t count) 277962306a36Sopenharmony_ci{ 278062306a36Sopenharmony_ci struct ptp_ocp *bp = dev_get_drvdata(dev); 278162306a36Sopenharmony_ci int err; 278262306a36Sopenharmony_ci 278362306a36Sopenharmony_ci err = ptp_ocp_sma_store(bp, buf, 4); 278462306a36Sopenharmony_ci return err ? err : count; 278562306a36Sopenharmony_ci} 278662306a36Sopenharmony_cistatic DEVICE_ATTR_RW(sma1); 278762306a36Sopenharmony_cistatic DEVICE_ATTR_RW(sma2); 278862306a36Sopenharmony_cistatic DEVICE_ATTR_RW(sma3); 278962306a36Sopenharmony_cistatic DEVICE_ATTR_RW(sma4); 279062306a36Sopenharmony_ci 279162306a36Sopenharmony_cistatic ssize_t 279262306a36Sopenharmony_ciavailable_sma_inputs_show(struct device *dev, 279362306a36Sopenharmony_ci struct device_attribute *attr, char *buf) 279462306a36Sopenharmony_ci{ 279562306a36Sopenharmony_ci struct ptp_ocp *bp = dev_get_drvdata(dev); 279662306a36Sopenharmony_ci 279762306a36Sopenharmony_ci return ptp_ocp_select_table_show(bp->sma_op->tbl[0], buf); 279862306a36Sopenharmony_ci} 279962306a36Sopenharmony_cistatic DEVICE_ATTR_RO(available_sma_inputs); 280062306a36Sopenharmony_ci 280162306a36Sopenharmony_cistatic ssize_t 280262306a36Sopenharmony_ciavailable_sma_outputs_show(struct device *dev, 280362306a36Sopenharmony_ci struct device_attribute *attr, char *buf) 280462306a36Sopenharmony_ci{ 280562306a36Sopenharmony_ci struct ptp_ocp *bp = dev_get_drvdata(dev); 280662306a36Sopenharmony_ci 280762306a36Sopenharmony_ci return ptp_ocp_select_table_show(bp->sma_op->tbl[1], buf); 280862306a36Sopenharmony_ci} 280962306a36Sopenharmony_cistatic DEVICE_ATTR_RO(available_sma_outputs); 281062306a36Sopenharmony_ci 281162306a36Sopenharmony_ci#define EXT_ATTR_RO(_group, _name, _val) \ 281262306a36Sopenharmony_ci struct dev_ext_attribute dev_attr_##_group##_val##_##_name = \ 281362306a36Sopenharmony_ci { __ATTR_RO(_name), (void *)_val } 281462306a36Sopenharmony_ci#define EXT_ATTR_RW(_group, _name, _val) \ 281562306a36Sopenharmony_ci struct dev_ext_attribute dev_attr_##_group##_val##_##_name = \ 281662306a36Sopenharmony_ci { __ATTR_RW(_name), (void *)_val } 281762306a36Sopenharmony_ci#define to_ext_attr(x) container_of(x, struct dev_ext_attribute, attr) 281862306a36Sopenharmony_ci 281962306a36Sopenharmony_ci/* period [duty [phase [polarity]]] */ 282062306a36Sopenharmony_cistatic ssize_t 282162306a36Sopenharmony_cisignal_store(struct device *dev, struct device_attribute *attr, 282262306a36Sopenharmony_ci const char *buf, size_t count) 282362306a36Sopenharmony_ci{ 282462306a36Sopenharmony_ci struct dev_ext_attribute *ea = to_ext_attr(attr); 282562306a36Sopenharmony_ci struct ptp_ocp *bp = dev_get_drvdata(dev); 282662306a36Sopenharmony_ci struct ptp_ocp_signal s = { }; 282762306a36Sopenharmony_ci int gen = (uintptr_t)ea->var; 282862306a36Sopenharmony_ci int argc, err; 282962306a36Sopenharmony_ci char **argv; 283062306a36Sopenharmony_ci 283162306a36Sopenharmony_ci argv = argv_split(GFP_KERNEL, buf, &argc); 283262306a36Sopenharmony_ci if (!argv) 283362306a36Sopenharmony_ci return -ENOMEM; 283462306a36Sopenharmony_ci 283562306a36Sopenharmony_ci err = -EINVAL; 283662306a36Sopenharmony_ci s.duty = bp->signal[gen].duty; 283762306a36Sopenharmony_ci s.phase = bp->signal[gen].phase; 283862306a36Sopenharmony_ci s.period = bp->signal[gen].period; 283962306a36Sopenharmony_ci s.polarity = bp->signal[gen].polarity; 284062306a36Sopenharmony_ci 284162306a36Sopenharmony_ci switch (argc) { 284262306a36Sopenharmony_ci case 4: 284362306a36Sopenharmony_ci argc--; 284462306a36Sopenharmony_ci err = kstrtobool(argv[argc], &s.polarity); 284562306a36Sopenharmony_ci if (err) 284662306a36Sopenharmony_ci goto out; 284762306a36Sopenharmony_ci fallthrough; 284862306a36Sopenharmony_ci case 3: 284962306a36Sopenharmony_ci argc--; 285062306a36Sopenharmony_ci err = kstrtou64(argv[argc], 0, &s.phase); 285162306a36Sopenharmony_ci if (err) 285262306a36Sopenharmony_ci goto out; 285362306a36Sopenharmony_ci fallthrough; 285462306a36Sopenharmony_ci case 2: 285562306a36Sopenharmony_ci argc--; 285662306a36Sopenharmony_ci err = kstrtoint(argv[argc], 0, &s.duty); 285762306a36Sopenharmony_ci if (err) 285862306a36Sopenharmony_ci goto out; 285962306a36Sopenharmony_ci fallthrough; 286062306a36Sopenharmony_ci case 1: 286162306a36Sopenharmony_ci argc--; 286262306a36Sopenharmony_ci err = kstrtou64(argv[argc], 0, &s.period); 286362306a36Sopenharmony_ci if (err) 286462306a36Sopenharmony_ci goto out; 286562306a36Sopenharmony_ci break; 286662306a36Sopenharmony_ci default: 286762306a36Sopenharmony_ci goto out; 286862306a36Sopenharmony_ci } 286962306a36Sopenharmony_ci 287062306a36Sopenharmony_ci err = ptp_ocp_signal_set(bp, gen, &s); 287162306a36Sopenharmony_ci if (err) 287262306a36Sopenharmony_ci goto out; 287362306a36Sopenharmony_ci 287462306a36Sopenharmony_ci err = ptp_ocp_signal_enable(bp->signal_out[gen], gen, s.period != 0); 287562306a36Sopenharmony_ci 287662306a36Sopenharmony_ciout: 287762306a36Sopenharmony_ci argv_free(argv); 287862306a36Sopenharmony_ci return err ? err : count; 287962306a36Sopenharmony_ci} 288062306a36Sopenharmony_ci 288162306a36Sopenharmony_cistatic ssize_t 288262306a36Sopenharmony_cisignal_show(struct device *dev, struct device_attribute *attr, char *buf) 288362306a36Sopenharmony_ci{ 288462306a36Sopenharmony_ci struct dev_ext_attribute *ea = to_ext_attr(attr); 288562306a36Sopenharmony_ci struct ptp_ocp *bp = dev_get_drvdata(dev); 288662306a36Sopenharmony_ci struct ptp_ocp_signal *signal; 288762306a36Sopenharmony_ci struct timespec64 ts; 288862306a36Sopenharmony_ci ssize_t count; 288962306a36Sopenharmony_ci int i; 289062306a36Sopenharmony_ci 289162306a36Sopenharmony_ci i = (uintptr_t)ea->var; 289262306a36Sopenharmony_ci signal = &bp->signal[i]; 289362306a36Sopenharmony_ci 289462306a36Sopenharmony_ci count = sysfs_emit(buf, "%llu %d %llu %d", signal->period, 289562306a36Sopenharmony_ci signal->duty, signal->phase, signal->polarity); 289662306a36Sopenharmony_ci 289762306a36Sopenharmony_ci ts = ktime_to_timespec64(signal->start); 289862306a36Sopenharmony_ci count += sysfs_emit_at(buf, count, " %ptT TAI\n", &ts); 289962306a36Sopenharmony_ci 290062306a36Sopenharmony_ci return count; 290162306a36Sopenharmony_ci} 290262306a36Sopenharmony_cistatic EXT_ATTR_RW(signal, signal, 0); 290362306a36Sopenharmony_cistatic EXT_ATTR_RW(signal, signal, 1); 290462306a36Sopenharmony_cistatic EXT_ATTR_RW(signal, signal, 2); 290562306a36Sopenharmony_cistatic EXT_ATTR_RW(signal, signal, 3); 290662306a36Sopenharmony_ci 290762306a36Sopenharmony_cistatic ssize_t 290862306a36Sopenharmony_ciduty_show(struct device *dev, struct device_attribute *attr, char *buf) 290962306a36Sopenharmony_ci{ 291062306a36Sopenharmony_ci struct dev_ext_attribute *ea = to_ext_attr(attr); 291162306a36Sopenharmony_ci struct ptp_ocp *bp = dev_get_drvdata(dev); 291262306a36Sopenharmony_ci int i = (uintptr_t)ea->var; 291362306a36Sopenharmony_ci 291462306a36Sopenharmony_ci return sysfs_emit(buf, "%d\n", bp->signal[i].duty); 291562306a36Sopenharmony_ci} 291662306a36Sopenharmony_cistatic EXT_ATTR_RO(signal, duty, 0); 291762306a36Sopenharmony_cistatic EXT_ATTR_RO(signal, duty, 1); 291862306a36Sopenharmony_cistatic EXT_ATTR_RO(signal, duty, 2); 291962306a36Sopenharmony_cistatic EXT_ATTR_RO(signal, duty, 3); 292062306a36Sopenharmony_ci 292162306a36Sopenharmony_cistatic ssize_t 292262306a36Sopenharmony_ciperiod_show(struct device *dev, struct device_attribute *attr, char *buf) 292362306a36Sopenharmony_ci{ 292462306a36Sopenharmony_ci struct dev_ext_attribute *ea = to_ext_attr(attr); 292562306a36Sopenharmony_ci struct ptp_ocp *bp = dev_get_drvdata(dev); 292662306a36Sopenharmony_ci int i = (uintptr_t)ea->var; 292762306a36Sopenharmony_ci 292862306a36Sopenharmony_ci return sysfs_emit(buf, "%llu\n", bp->signal[i].period); 292962306a36Sopenharmony_ci} 293062306a36Sopenharmony_cistatic EXT_ATTR_RO(signal, period, 0); 293162306a36Sopenharmony_cistatic EXT_ATTR_RO(signal, period, 1); 293262306a36Sopenharmony_cistatic EXT_ATTR_RO(signal, period, 2); 293362306a36Sopenharmony_cistatic EXT_ATTR_RO(signal, period, 3); 293462306a36Sopenharmony_ci 293562306a36Sopenharmony_cistatic ssize_t 293662306a36Sopenharmony_ciphase_show(struct device *dev, struct device_attribute *attr, char *buf) 293762306a36Sopenharmony_ci{ 293862306a36Sopenharmony_ci struct dev_ext_attribute *ea = to_ext_attr(attr); 293962306a36Sopenharmony_ci struct ptp_ocp *bp = dev_get_drvdata(dev); 294062306a36Sopenharmony_ci int i = (uintptr_t)ea->var; 294162306a36Sopenharmony_ci 294262306a36Sopenharmony_ci return sysfs_emit(buf, "%llu\n", bp->signal[i].phase); 294362306a36Sopenharmony_ci} 294462306a36Sopenharmony_cistatic EXT_ATTR_RO(signal, phase, 0); 294562306a36Sopenharmony_cistatic EXT_ATTR_RO(signal, phase, 1); 294662306a36Sopenharmony_cistatic EXT_ATTR_RO(signal, phase, 2); 294762306a36Sopenharmony_cistatic EXT_ATTR_RO(signal, phase, 3); 294862306a36Sopenharmony_ci 294962306a36Sopenharmony_cistatic ssize_t 295062306a36Sopenharmony_cipolarity_show(struct device *dev, struct device_attribute *attr, 295162306a36Sopenharmony_ci char *buf) 295262306a36Sopenharmony_ci{ 295362306a36Sopenharmony_ci struct dev_ext_attribute *ea = to_ext_attr(attr); 295462306a36Sopenharmony_ci struct ptp_ocp *bp = dev_get_drvdata(dev); 295562306a36Sopenharmony_ci int i = (uintptr_t)ea->var; 295662306a36Sopenharmony_ci 295762306a36Sopenharmony_ci return sysfs_emit(buf, "%d\n", bp->signal[i].polarity); 295862306a36Sopenharmony_ci} 295962306a36Sopenharmony_cistatic EXT_ATTR_RO(signal, polarity, 0); 296062306a36Sopenharmony_cistatic EXT_ATTR_RO(signal, polarity, 1); 296162306a36Sopenharmony_cistatic EXT_ATTR_RO(signal, polarity, 2); 296262306a36Sopenharmony_cistatic EXT_ATTR_RO(signal, polarity, 3); 296362306a36Sopenharmony_ci 296462306a36Sopenharmony_cistatic ssize_t 296562306a36Sopenharmony_cirunning_show(struct device *dev, struct device_attribute *attr, char *buf) 296662306a36Sopenharmony_ci{ 296762306a36Sopenharmony_ci struct dev_ext_attribute *ea = to_ext_attr(attr); 296862306a36Sopenharmony_ci struct ptp_ocp *bp = dev_get_drvdata(dev); 296962306a36Sopenharmony_ci int i = (uintptr_t)ea->var; 297062306a36Sopenharmony_ci 297162306a36Sopenharmony_ci return sysfs_emit(buf, "%d\n", bp->signal[i].running); 297262306a36Sopenharmony_ci} 297362306a36Sopenharmony_cistatic EXT_ATTR_RO(signal, running, 0); 297462306a36Sopenharmony_cistatic EXT_ATTR_RO(signal, running, 1); 297562306a36Sopenharmony_cistatic EXT_ATTR_RO(signal, running, 2); 297662306a36Sopenharmony_cistatic EXT_ATTR_RO(signal, running, 3); 297762306a36Sopenharmony_ci 297862306a36Sopenharmony_cistatic ssize_t 297962306a36Sopenharmony_cistart_show(struct device *dev, struct device_attribute *attr, char *buf) 298062306a36Sopenharmony_ci{ 298162306a36Sopenharmony_ci struct dev_ext_attribute *ea = to_ext_attr(attr); 298262306a36Sopenharmony_ci struct ptp_ocp *bp = dev_get_drvdata(dev); 298362306a36Sopenharmony_ci int i = (uintptr_t)ea->var; 298462306a36Sopenharmony_ci struct timespec64 ts; 298562306a36Sopenharmony_ci 298662306a36Sopenharmony_ci ts = ktime_to_timespec64(bp->signal[i].start); 298762306a36Sopenharmony_ci return sysfs_emit(buf, "%llu.%lu\n", ts.tv_sec, ts.tv_nsec); 298862306a36Sopenharmony_ci} 298962306a36Sopenharmony_cistatic EXT_ATTR_RO(signal, start, 0); 299062306a36Sopenharmony_cistatic EXT_ATTR_RO(signal, start, 1); 299162306a36Sopenharmony_cistatic EXT_ATTR_RO(signal, start, 2); 299262306a36Sopenharmony_cistatic EXT_ATTR_RO(signal, start, 3); 299362306a36Sopenharmony_ci 299462306a36Sopenharmony_cistatic ssize_t 299562306a36Sopenharmony_ciseconds_store(struct device *dev, struct device_attribute *attr, 299662306a36Sopenharmony_ci const char *buf, size_t count) 299762306a36Sopenharmony_ci{ 299862306a36Sopenharmony_ci struct dev_ext_attribute *ea = to_ext_attr(attr); 299962306a36Sopenharmony_ci struct ptp_ocp *bp = dev_get_drvdata(dev); 300062306a36Sopenharmony_ci int idx = (uintptr_t)ea->var; 300162306a36Sopenharmony_ci u32 val; 300262306a36Sopenharmony_ci int err; 300362306a36Sopenharmony_ci 300462306a36Sopenharmony_ci err = kstrtou32(buf, 0, &val); 300562306a36Sopenharmony_ci if (err) 300662306a36Sopenharmony_ci return err; 300762306a36Sopenharmony_ci if (val > 0xff) 300862306a36Sopenharmony_ci return -EINVAL; 300962306a36Sopenharmony_ci 301062306a36Sopenharmony_ci if (val) 301162306a36Sopenharmony_ci val = (val << 8) | 0x1; 301262306a36Sopenharmony_ci 301362306a36Sopenharmony_ci iowrite32(val, &bp->freq_in[idx]->ctrl); 301462306a36Sopenharmony_ci 301562306a36Sopenharmony_ci return count; 301662306a36Sopenharmony_ci} 301762306a36Sopenharmony_ci 301862306a36Sopenharmony_cistatic ssize_t 301962306a36Sopenharmony_ciseconds_show(struct device *dev, struct device_attribute *attr, char *buf) 302062306a36Sopenharmony_ci{ 302162306a36Sopenharmony_ci struct dev_ext_attribute *ea = to_ext_attr(attr); 302262306a36Sopenharmony_ci struct ptp_ocp *bp = dev_get_drvdata(dev); 302362306a36Sopenharmony_ci int idx = (uintptr_t)ea->var; 302462306a36Sopenharmony_ci u32 val; 302562306a36Sopenharmony_ci 302662306a36Sopenharmony_ci val = ioread32(&bp->freq_in[idx]->ctrl); 302762306a36Sopenharmony_ci if (val & 1) 302862306a36Sopenharmony_ci val = (val >> 8) & 0xff; 302962306a36Sopenharmony_ci else 303062306a36Sopenharmony_ci val = 0; 303162306a36Sopenharmony_ci 303262306a36Sopenharmony_ci return sysfs_emit(buf, "%u\n", val); 303362306a36Sopenharmony_ci} 303462306a36Sopenharmony_cistatic EXT_ATTR_RW(freq, seconds, 0); 303562306a36Sopenharmony_cistatic EXT_ATTR_RW(freq, seconds, 1); 303662306a36Sopenharmony_cistatic EXT_ATTR_RW(freq, seconds, 2); 303762306a36Sopenharmony_cistatic EXT_ATTR_RW(freq, seconds, 3); 303862306a36Sopenharmony_ci 303962306a36Sopenharmony_cistatic ssize_t 304062306a36Sopenharmony_cifrequency_show(struct device *dev, struct device_attribute *attr, char *buf) 304162306a36Sopenharmony_ci{ 304262306a36Sopenharmony_ci struct dev_ext_attribute *ea = to_ext_attr(attr); 304362306a36Sopenharmony_ci struct ptp_ocp *bp = dev_get_drvdata(dev); 304462306a36Sopenharmony_ci int idx = (uintptr_t)ea->var; 304562306a36Sopenharmony_ci u32 val; 304662306a36Sopenharmony_ci 304762306a36Sopenharmony_ci val = ioread32(&bp->freq_in[idx]->status); 304862306a36Sopenharmony_ci if (val & FREQ_STATUS_ERROR) 304962306a36Sopenharmony_ci return sysfs_emit(buf, "error\n"); 305062306a36Sopenharmony_ci if (val & FREQ_STATUS_OVERRUN) 305162306a36Sopenharmony_ci return sysfs_emit(buf, "overrun\n"); 305262306a36Sopenharmony_ci if (val & FREQ_STATUS_VALID) 305362306a36Sopenharmony_ci return sysfs_emit(buf, "%lu\n", val & FREQ_STATUS_MASK); 305462306a36Sopenharmony_ci return 0; 305562306a36Sopenharmony_ci} 305662306a36Sopenharmony_cistatic EXT_ATTR_RO(freq, frequency, 0); 305762306a36Sopenharmony_cistatic EXT_ATTR_RO(freq, frequency, 1); 305862306a36Sopenharmony_cistatic EXT_ATTR_RO(freq, frequency, 2); 305962306a36Sopenharmony_cistatic EXT_ATTR_RO(freq, frequency, 3); 306062306a36Sopenharmony_ci 306162306a36Sopenharmony_cistatic ssize_t 306262306a36Sopenharmony_ciserialnum_show(struct device *dev, struct device_attribute *attr, char *buf) 306362306a36Sopenharmony_ci{ 306462306a36Sopenharmony_ci struct ptp_ocp *bp = dev_get_drvdata(dev); 306562306a36Sopenharmony_ci 306662306a36Sopenharmony_ci if (!bp->has_eeprom_data) 306762306a36Sopenharmony_ci ptp_ocp_read_eeprom(bp); 306862306a36Sopenharmony_ci 306962306a36Sopenharmony_ci return sysfs_emit(buf, "%pM\n", bp->serial); 307062306a36Sopenharmony_ci} 307162306a36Sopenharmony_cistatic DEVICE_ATTR_RO(serialnum); 307262306a36Sopenharmony_ci 307362306a36Sopenharmony_cistatic ssize_t 307462306a36Sopenharmony_cignss_sync_show(struct device *dev, struct device_attribute *attr, char *buf) 307562306a36Sopenharmony_ci{ 307662306a36Sopenharmony_ci struct ptp_ocp *bp = dev_get_drvdata(dev); 307762306a36Sopenharmony_ci ssize_t ret; 307862306a36Sopenharmony_ci 307962306a36Sopenharmony_ci if (bp->gnss_lost) 308062306a36Sopenharmony_ci ret = sysfs_emit(buf, "LOST @ %ptT\n", &bp->gnss_lost); 308162306a36Sopenharmony_ci else 308262306a36Sopenharmony_ci ret = sysfs_emit(buf, "SYNC\n"); 308362306a36Sopenharmony_ci 308462306a36Sopenharmony_ci return ret; 308562306a36Sopenharmony_ci} 308662306a36Sopenharmony_cistatic DEVICE_ATTR_RO(gnss_sync); 308762306a36Sopenharmony_ci 308862306a36Sopenharmony_cistatic ssize_t 308962306a36Sopenharmony_ciutc_tai_offset_show(struct device *dev, 309062306a36Sopenharmony_ci struct device_attribute *attr, char *buf) 309162306a36Sopenharmony_ci{ 309262306a36Sopenharmony_ci struct ptp_ocp *bp = dev_get_drvdata(dev); 309362306a36Sopenharmony_ci 309462306a36Sopenharmony_ci return sysfs_emit(buf, "%d\n", bp->utc_tai_offset); 309562306a36Sopenharmony_ci} 309662306a36Sopenharmony_ci 309762306a36Sopenharmony_cistatic ssize_t 309862306a36Sopenharmony_ciutc_tai_offset_store(struct device *dev, 309962306a36Sopenharmony_ci struct device_attribute *attr, 310062306a36Sopenharmony_ci const char *buf, size_t count) 310162306a36Sopenharmony_ci{ 310262306a36Sopenharmony_ci struct ptp_ocp *bp = dev_get_drvdata(dev); 310362306a36Sopenharmony_ci int err; 310462306a36Sopenharmony_ci u32 val; 310562306a36Sopenharmony_ci 310662306a36Sopenharmony_ci err = kstrtou32(buf, 0, &val); 310762306a36Sopenharmony_ci if (err) 310862306a36Sopenharmony_ci return err; 310962306a36Sopenharmony_ci 311062306a36Sopenharmony_ci ptp_ocp_utc_distribute(bp, val); 311162306a36Sopenharmony_ci 311262306a36Sopenharmony_ci return count; 311362306a36Sopenharmony_ci} 311462306a36Sopenharmony_cistatic DEVICE_ATTR_RW(utc_tai_offset); 311562306a36Sopenharmony_ci 311662306a36Sopenharmony_cistatic ssize_t 311762306a36Sopenharmony_cits_window_adjust_show(struct device *dev, 311862306a36Sopenharmony_ci struct device_attribute *attr, char *buf) 311962306a36Sopenharmony_ci{ 312062306a36Sopenharmony_ci struct ptp_ocp *bp = dev_get_drvdata(dev); 312162306a36Sopenharmony_ci 312262306a36Sopenharmony_ci return sysfs_emit(buf, "%d\n", bp->ts_window_adjust); 312362306a36Sopenharmony_ci} 312462306a36Sopenharmony_ci 312562306a36Sopenharmony_cistatic ssize_t 312662306a36Sopenharmony_cits_window_adjust_store(struct device *dev, 312762306a36Sopenharmony_ci struct device_attribute *attr, 312862306a36Sopenharmony_ci const char *buf, size_t count) 312962306a36Sopenharmony_ci{ 313062306a36Sopenharmony_ci struct ptp_ocp *bp = dev_get_drvdata(dev); 313162306a36Sopenharmony_ci int err; 313262306a36Sopenharmony_ci u32 val; 313362306a36Sopenharmony_ci 313462306a36Sopenharmony_ci err = kstrtou32(buf, 0, &val); 313562306a36Sopenharmony_ci if (err) 313662306a36Sopenharmony_ci return err; 313762306a36Sopenharmony_ci 313862306a36Sopenharmony_ci bp->ts_window_adjust = val; 313962306a36Sopenharmony_ci 314062306a36Sopenharmony_ci return count; 314162306a36Sopenharmony_ci} 314262306a36Sopenharmony_cistatic DEVICE_ATTR_RW(ts_window_adjust); 314362306a36Sopenharmony_ci 314462306a36Sopenharmony_cistatic ssize_t 314562306a36Sopenharmony_ciirig_b_mode_show(struct device *dev, struct device_attribute *attr, char *buf) 314662306a36Sopenharmony_ci{ 314762306a36Sopenharmony_ci struct ptp_ocp *bp = dev_get_drvdata(dev); 314862306a36Sopenharmony_ci u32 val; 314962306a36Sopenharmony_ci 315062306a36Sopenharmony_ci val = ioread32(&bp->irig_out->ctrl); 315162306a36Sopenharmony_ci val = (val >> 16) & 0x07; 315262306a36Sopenharmony_ci return sysfs_emit(buf, "%d\n", val); 315362306a36Sopenharmony_ci} 315462306a36Sopenharmony_ci 315562306a36Sopenharmony_cistatic ssize_t 315662306a36Sopenharmony_ciirig_b_mode_store(struct device *dev, 315762306a36Sopenharmony_ci struct device_attribute *attr, 315862306a36Sopenharmony_ci const char *buf, size_t count) 315962306a36Sopenharmony_ci{ 316062306a36Sopenharmony_ci struct ptp_ocp *bp = dev_get_drvdata(dev); 316162306a36Sopenharmony_ci unsigned long flags; 316262306a36Sopenharmony_ci int err; 316362306a36Sopenharmony_ci u32 reg; 316462306a36Sopenharmony_ci u8 val; 316562306a36Sopenharmony_ci 316662306a36Sopenharmony_ci err = kstrtou8(buf, 0, &val); 316762306a36Sopenharmony_ci if (err) 316862306a36Sopenharmony_ci return err; 316962306a36Sopenharmony_ci if (val > 7) 317062306a36Sopenharmony_ci return -EINVAL; 317162306a36Sopenharmony_ci 317262306a36Sopenharmony_ci reg = ((val & 0x7) << 16); 317362306a36Sopenharmony_ci 317462306a36Sopenharmony_ci spin_lock_irqsave(&bp->lock, flags); 317562306a36Sopenharmony_ci iowrite32(0, &bp->irig_out->ctrl); /* disable */ 317662306a36Sopenharmony_ci iowrite32(reg, &bp->irig_out->ctrl); /* change mode */ 317762306a36Sopenharmony_ci iowrite32(reg | IRIG_M_CTRL_ENABLE, &bp->irig_out->ctrl); 317862306a36Sopenharmony_ci spin_unlock_irqrestore(&bp->lock, flags); 317962306a36Sopenharmony_ci 318062306a36Sopenharmony_ci return count; 318162306a36Sopenharmony_ci} 318262306a36Sopenharmony_cistatic DEVICE_ATTR_RW(irig_b_mode); 318362306a36Sopenharmony_ci 318462306a36Sopenharmony_cistatic ssize_t 318562306a36Sopenharmony_ciclock_source_show(struct device *dev, struct device_attribute *attr, char *buf) 318662306a36Sopenharmony_ci{ 318762306a36Sopenharmony_ci struct ptp_ocp *bp = dev_get_drvdata(dev); 318862306a36Sopenharmony_ci const char *p; 318962306a36Sopenharmony_ci u32 select; 319062306a36Sopenharmony_ci 319162306a36Sopenharmony_ci select = ioread32(&bp->reg->select); 319262306a36Sopenharmony_ci p = ptp_ocp_select_name_from_val(ptp_ocp_clock, select >> 16); 319362306a36Sopenharmony_ci 319462306a36Sopenharmony_ci return sysfs_emit(buf, "%s\n", p); 319562306a36Sopenharmony_ci} 319662306a36Sopenharmony_ci 319762306a36Sopenharmony_cistatic ssize_t 319862306a36Sopenharmony_ciclock_source_store(struct device *dev, struct device_attribute *attr, 319962306a36Sopenharmony_ci const char *buf, size_t count) 320062306a36Sopenharmony_ci{ 320162306a36Sopenharmony_ci struct ptp_ocp *bp = dev_get_drvdata(dev); 320262306a36Sopenharmony_ci unsigned long flags; 320362306a36Sopenharmony_ci int val; 320462306a36Sopenharmony_ci 320562306a36Sopenharmony_ci val = ptp_ocp_select_val_from_name(ptp_ocp_clock, buf); 320662306a36Sopenharmony_ci if (val < 0) 320762306a36Sopenharmony_ci return val; 320862306a36Sopenharmony_ci 320962306a36Sopenharmony_ci spin_lock_irqsave(&bp->lock, flags); 321062306a36Sopenharmony_ci iowrite32(val, &bp->reg->select); 321162306a36Sopenharmony_ci spin_unlock_irqrestore(&bp->lock, flags); 321262306a36Sopenharmony_ci 321362306a36Sopenharmony_ci return count; 321462306a36Sopenharmony_ci} 321562306a36Sopenharmony_cistatic DEVICE_ATTR_RW(clock_source); 321662306a36Sopenharmony_ci 321762306a36Sopenharmony_cistatic ssize_t 321862306a36Sopenharmony_ciavailable_clock_sources_show(struct device *dev, 321962306a36Sopenharmony_ci struct device_attribute *attr, char *buf) 322062306a36Sopenharmony_ci{ 322162306a36Sopenharmony_ci return ptp_ocp_select_table_show(ptp_ocp_clock, buf); 322262306a36Sopenharmony_ci} 322362306a36Sopenharmony_cistatic DEVICE_ATTR_RO(available_clock_sources); 322462306a36Sopenharmony_ci 322562306a36Sopenharmony_cistatic ssize_t 322662306a36Sopenharmony_ciclock_status_drift_show(struct device *dev, 322762306a36Sopenharmony_ci struct device_attribute *attr, char *buf) 322862306a36Sopenharmony_ci{ 322962306a36Sopenharmony_ci struct ptp_ocp *bp = dev_get_drvdata(dev); 323062306a36Sopenharmony_ci u32 val; 323162306a36Sopenharmony_ci int res; 323262306a36Sopenharmony_ci 323362306a36Sopenharmony_ci val = ioread32(&bp->reg->status_drift); 323462306a36Sopenharmony_ci res = (val & ~INT_MAX) ? -1 : 1; 323562306a36Sopenharmony_ci res *= (val & INT_MAX); 323662306a36Sopenharmony_ci return sysfs_emit(buf, "%d\n", res); 323762306a36Sopenharmony_ci} 323862306a36Sopenharmony_cistatic DEVICE_ATTR_RO(clock_status_drift); 323962306a36Sopenharmony_ci 324062306a36Sopenharmony_cistatic ssize_t 324162306a36Sopenharmony_ciclock_status_offset_show(struct device *dev, 324262306a36Sopenharmony_ci struct device_attribute *attr, char *buf) 324362306a36Sopenharmony_ci{ 324462306a36Sopenharmony_ci struct ptp_ocp *bp = dev_get_drvdata(dev); 324562306a36Sopenharmony_ci u32 val; 324662306a36Sopenharmony_ci int res; 324762306a36Sopenharmony_ci 324862306a36Sopenharmony_ci val = ioread32(&bp->reg->status_offset); 324962306a36Sopenharmony_ci res = (val & ~INT_MAX) ? -1 : 1; 325062306a36Sopenharmony_ci res *= (val & INT_MAX); 325162306a36Sopenharmony_ci return sysfs_emit(buf, "%d\n", res); 325262306a36Sopenharmony_ci} 325362306a36Sopenharmony_cistatic DEVICE_ATTR_RO(clock_status_offset); 325462306a36Sopenharmony_ci 325562306a36Sopenharmony_cistatic ssize_t 325662306a36Sopenharmony_citod_correction_show(struct device *dev, 325762306a36Sopenharmony_ci struct device_attribute *attr, char *buf) 325862306a36Sopenharmony_ci{ 325962306a36Sopenharmony_ci struct ptp_ocp *bp = dev_get_drvdata(dev); 326062306a36Sopenharmony_ci u32 val; 326162306a36Sopenharmony_ci int res; 326262306a36Sopenharmony_ci 326362306a36Sopenharmony_ci val = ioread32(&bp->tod->adj_sec); 326462306a36Sopenharmony_ci res = (val & ~INT_MAX) ? -1 : 1; 326562306a36Sopenharmony_ci res *= (val & INT_MAX); 326662306a36Sopenharmony_ci return sysfs_emit(buf, "%d\n", res); 326762306a36Sopenharmony_ci} 326862306a36Sopenharmony_ci 326962306a36Sopenharmony_cistatic ssize_t 327062306a36Sopenharmony_citod_correction_store(struct device *dev, struct device_attribute *attr, 327162306a36Sopenharmony_ci const char *buf, size_t count) 327262306a36Sopenharmony_ci{ 327362306a36Sopenharmony_ci struct ptp_ocp *bp = dev_get_drvdata(dev); 327462306a36Sopenharmony_ci unsigned long flags; 327562306a36Sopenharmony_ci int err, res; 327662306a36Sopenharmony_ci u32 val = 0; 327762306a36Sopenharmony_ci 327862306a36Sopenharmony_ci err = kstrtos32(buf, 0, &res); 327962306a36Sopenharmony_ci if (err) 328062306a36Sopenharmony_ci return err; 328162306a36Sopenharmony_ci if (res < 0) { 328262306a36Sopenharmony_ci res *= -1; 328362306a36Sopenharmony_ci val |= BIT(31); 328462306a36Sopenharmony_ci } 328562306a36Sopenharmony_ci val |= res; 328662306a36Sopenharmony_ci 328762306a36Sopenharmony_ci spin_lock_irqsave(&bp->lock, flags); 328862306a36Sopenharmony_ci iowrite32(val, &bp->tod->adj_sec); 328962306a36Sopenharmony_ci spin_unlock_irqrestore(&bp->lock, flags); 329062306a36Sopenharmony_ci 329162306a36Sopenharmony_ci return count; 329262306a36Sopenharmony_ci} 329362306a36Sopenharmony_cistatic DEVICE_ATTR_RW(tod_correction); 329462306a36Sopenharmony_ci 329562306a36Sopenharmony_ci#define _DEVICE_SIGNAL_GROUP_ATTRS(_nr) \ 329662306a36Sopenharmony_ci static struct attribute *fb_timecard_signal##_nr##_attrs[] = { \ 329762306a36Sopenharmony_ci &dev_attr_signal##_nr##_signal.attr.attr, \ 329862306a36Sopenharmony_ci &dev_attr_signal##_nr##_duty.attr.attr, \ 329962306a36Sopenharmony_ci &dev_attr_signal##_nr##_phase.attr.attr, \ 330062306a36Sopenharmony_ci &dev_attr_signal##_nr##_period.attr.attr, \ 330162306a36Sopenharmony_ci &dev_attr_signal##_nr##_polarity.attr.attr, \ 330262306a36Sopenharmony_ci &dev_attr_signal##_nr##_running.attr.attr, \ 330362306a36Sopenharmony_ci &dev_attr_signal##_nr##_start.attr.attr, \ 330462306a36Sopenharmony_ci NULL, \ 330562306a36Sopenharmony_ci } 330662306a36Sopenharmony_ci 330762306a36Sopenharmony_ci#define DEVICE_SIGNAL_GROUP(_name, _nr) \ 330862306a36Sopenharmony_ci _DEVICE_SIGNAL_GROUP_ATTRS(_nr); \ 330962306a36Sopenharmony_ci static const struct attribute_group \ 331062306a36Sopenharmony_ci fb_timecard_signal##_nr##_group = { \ 331162306a36Sopenharmony_ci .name = #_name, \ 331262306a36Sopenharmony_ci .attrs = fb_timecard_signal##_nr##_attrs, \ 331362306a36Sopenharmony_ci} 331462306a36Sopenharmony_ci 331562306a36Sopenharmony_ciDEVICE_SIGNAL_GROUP(gen1, 0); 331662306a36Sopenharmony_ciDEVICE_SIGNAL_GROUP(gen2, 1); 331762306a36Sopenharmony_ciDEVICE_SIGNAL_GROUP(gen3, 2); 331862306a36Sopenharmony_ciDEVICE_SIGNAL_GROUP(gen4, 3); 331962306a36Sopenharmony_ci 332062306a36Sopenharmony_ci#define _DEVICE_FREQ_GROUP_ATTRS(_nr) \ 332162306a36Sopenharmony_ci static struct attribute *fb_timecard_freq##_nr##_attrs[] = { \ 332262306a36Sopenharmony_ci &dev_attr_freq##_nr##_seconds.attr.attr, \ 332362306a36Sopenharmony_ci &dev_attr_freq##_nr##_frequency.attr.attr, \ 332462306a36Sopenharmony_ci NULL, \ 332562306a36Sopenharmony_ci } 332662306a36Sopenharmony_ci 332762306a36Sopenharmony_ci#define DEVICE_FREQ_GROUP(_name, _nr) \ 332862306a36Sopenharmony_ci _DEVICE_FREQ_GROUP_ATTRS(_nr); \ 332962306a36Sopenharmony_ci static const struct attribute_group \ 333062306a36Sopenharmony_ci fb_timecard_freq##_nr##_group = { \ 333162306a36Sopenharmony_ci .name = #_name, \ 333262306a36Sopenharmony_ci .attrs = fb_timecard_freq##_nr##_attrs, \ 333362306a36Sopenharmony_ci} 333462306a36Sopenharmony_ci 333562306a36Sopenharmony_ciDEVICE_FREQ_GROUP(freq1, 0); 333662306a36Sopenharmony_ciDEVICE_FREQ_GROUP(freq2, 1); 333762306a36Sopenharmony_ciDEVICE_FREQ_GROUP(freq3, 2); 333862306a36Sopenharmony_ciDEVICE_FREQ_GROUP(freq4, 3); 333962306a36Sopenharmony_ci 334062306a36Sopenharmony_cistatic ssize_t 334162306a36Sopenharmony_cidisciplining_config_read(struct file *filp, struct kobject *kobj, 334262306a36Sopenharmony_ci struct bin_attribute *bin_attr, char *buf, 334362306a36Sopenharmony_ci loff_t off, size_t count) 334462306a36Sopenharmony_ci{ 334562306a36Sopenharmony_ci struct ptp_ocp *bp = dev_get_drvdata(kobj_to_dev(kobj)); 334662306a36Sopenharmony_ci size_t size = OCP_ART_CONFIG_SIZE; 334762306a36Sopenharmony_ci struct nvmem_device *nvmem; 334862306a36Sopenharmony_ci ssize_t err; 334962306a36Sopenharmony_ci 335062306a36Sopenharmony_ci nvmem = ptp_ocp_nvmem_device_get(bp, NULL); 335162306a36Sopenharmony_ci if (IS_ERR(nvmem)) 335262306a36Sopenharmony_ci return PTR_ERR(nvmem); 335362306a36Sopenharmony_ci 335462306a36Sopenharmony_ci if (off > size) { 335562306a36Sopenharmony_ci err = 0; 335662306a36Sopenharmony_ci goto out; 335762306a36Sopenharmony_ci } 335862306a36Sopenharmony_ci 335962306a36Sopenharmony_ci if (off + count > size) 336062306a36Sopenharmony_ci count = size - off; 336162306a36Sopenharmony_ci 336262306a36Sopenharmony_ci // the configuration is in the very beginning of the EEPROM 336362306a36Sopenharmony_ci err = nvmem_device_read(nvmem, off, count, buf); 336462306a36Sopenharmony_ci if (err != count) { 336562306a36Sopenharmony_ci err = -EFAULT; 336662306a36Sopenharmony_ci goto out; 336762306a36Sopenharmony_ci } 336862306a36Sopenharmony_ci 336962306a36Sopenharmony_ciout: 337062306a36Sopenharmony_ci ptp_ocp_nvmem_device_put(&nvmem); 337162306a36Sopenharmony_ci 337262306a36Sopenharmony_ci return err; 337362306a36Sopenharmony_ci} 337462306a36Sopenharmony_ci 337562306a36Sopenharmony_cistatic ssize_t 337662306a36Sopenharmony_cidisciplining_config_write(struct file *filp, struct kobject *kobj, 337762306a36Sopenharmony_ci struct bin_attribute *bin_attr, char *buf, 337862306a36Sopenharmony_ci loff_t off, size_t count) 337962306a36Sopenharmony_ci{ 338062306a36Sopenharmony_ci struct ptp_ocp *bp = dev_get_drvdata(kobj_to_dev(kobj)); 338162306a36Sopenharmony_ci struct nvmem_device *nvmem; 338262306a36Sopenharmony_ci ssize_t err; 338362306a36Sopenharmony_ci 338462306a36Sopenharmony_ci /* Allow write of the whole area only */ 338562306a36Sopenharmony_ci if (off || count != OCP_ART_CONFIG_SIZE) 338662306a36Sopenharmony_ci return -EFAULT; 338762306a36Sopenharmony_ci 338862306a36Sopenharmony_ci nvmem = ptp_ocp_nvmem_device_get(bp, NULL); 338962306a36Sopenharmony_ci if (IS_ERR(nvmem)) 339062306a36Sopenharmony_ci return PTR_ERR(nvmem); 339162306a36Sopenharmony_ci 339262306a36Sopenharmony_ci err = nvmem_device_write(nvmem, 0x00, count, buf); 339362306a36Sopenharmony_ci if (err != count) 339462306a36Sopenharmony_ci err = -EFAULT; 339562306a36Sopenharmony_ci 339662306a36Sopenharmony_ci ptp_ocp_nvmem_device_put(&nvmem); 339762306a36Sopenharmony_ci 339862306a36Sopenharmony_ci return err; 339962306a36Sopenharmony_ci} 340062306a36Sopenharmony_cistatic BIN_ATTR_RW(disciplining_config, OCP_ART_CONFIG_SIZE); 340162306a36Sopenharmony_ci 340262306a36Sopenharmony_cistatic ssize_t 340362306a36Sopenharmony_citemperature_table_read(struct file *filp, struct kobject *kobj, 340462306a36Sopenharmony_ci struct bin_attribute *bin_attr, char *buf, 340562306a36Sopenharmony_ci loff_t off, size_t count) 340662306a36Sopenharmony_ci{ 340762306a36Sopenharmony_ci struct ptp_ocp *bp = dev_get_drvdata(kobj_to_dev(kobj)); 340862306a36Sopenharmony_ci size_t size = OCP_ART_TEMP_TABLE_SIZE; 340962306a36Sopenharmony_ci struct nvmem_device *nvmem; 341062306a36Sopenharmony_ci ssize_t err; 341162306a36Sopenharmony_ci 341262306a36Sopenharmony_ci nvmem = ptp_ocp_nvmem_device_get(bp, NULL); 341362306a36Sopenharmony_ci if (IS_ERR(nvmem)) 341462306a36Sopenharmony_ci return PTR_ERR(nvmem); 341562306a36Sopenharmony_ci 341662306a36Sopenharmony_ci if (off > size) { 341762306a36Sopenharmony_ci err = 0; 341862306a36Sopenharmony_ci goto out; 341962306a36Sopenharmony_ci } 342062306a36Sopenharmony_ci 342162306a36Sopenharmony_ci if (off + count > size) 342262306a36Sopenharmony_ci count = size - off; 342362306a36Sopenharmony_ci 342462306a36Sopenharmony_ci // the configuration is in the very beginning of the EEPROM 342562306a36Sopenharmony_ci err = nvmem_device_read(nvmem, 0x90 + off, count, buf); 342662306a36Sopenharmony_ci if (err != count) { 342762306a36Sopenharmony_ci err = -EFAULT; 342862306a36Sopenharmony_ci goto out; 342962306a36Sopenharmony_ci } 343062306a36Sopenharmony_ci 343162306a36Sopenharmony_ciout: 343262306a36Sopenharmony_ci ptp_ocp_nvmem_device_put(&nvmem); 343362306a36Sopenharmony_ci 343462306a36Sopenharmony_ci return err; 343562306a36Sopenharmony_ci} 343662306a36Sopenharmony_ci 343762306a36Sopenharmony_cistatic ssize_t 343862306a36Sopenharmony_citemperature_table_write(struct file *filp, struct kobject *kobj, 343962306a36Sopenharmony_ci struct bin_attribute *bin_attr, char *buf, 344062306a36Sopenharmony_ci loff_t off, size_t count) 344162306a36Sopenharmony_ci{ 344262306a36Sopenharmony_ci struct ptp_ocp *bp = dev_get_drvdata(kobj_to_dev(kobj)); 344362306a36Sopenharmony_ci struct nvmem_device *nvmem; 344462306a36Sopenharmony_ci ssize_t err; 344562306a36Sopenharmony_ci 344662306a36Sopenharmony_ci /* Allow write of the whole area only */ 344762306a36Sopenharmony_ci if (off || count != OCP_ART_TEMP_TABLE_SIZE) 344862306a36Sopenharmony_ci return -EFAULT; 344962306a36Sopenharmony_ci 345062306a36Sopenharmony_ci nvmem = ptp_ocp_nvmem_device_get(bp, NULL); 345162306a36Sopenharmony_ci if (IS_ERR(nvmem)) 345262306a36Sopenharmony_ci return PTR_ERR(nvmem); 345362306a36Sopenharmony_ci 345462306a36Sopenharmony_ci err = nvmem_device_write(nvmem, 0x90, count, buf); 345562306a36Sopenharmony_ci if (err != count) 345662306a36Sopenharmony_ci err = -EFAULT; 345762306a36Sopenharmony_ci 345862306a36Sopenharmony_ci ptp_ocp_nvmem_device_put(&nvmem); 345962306a36Sopenharmony_ci 346062306a36Sopenharmony_ci return err; 346162306a36Sopenharmony_ci} 346262306a36Sopenharmony_cistatic BIN_ATTR_RW(temperature_table, OCP_ART_TEMP_TABLE_SIZE); 346362306a36Sopenharmony_ci 346462306a36Sopenharmony_cistatic struct attribute *fb_timecard_attrs[] = { 346562306a36Sopenharmony_ci &dev_attr_serialnum.attr, 346662306a36Sopenharmony_ci &dev_attr_gnss_sync.attr, 346762306a36Sopenharmony_ci &dev_attr_clock_source.attr, 346862306a36Sopenharmony_ci &dev_attr_available_clock_sources.attr, 346962306a36Sopenharmony_ci &dev_attr_sma1.attr, 347062306a36Sopenharmony_ci &dev_attr_sma2.attr, 347162306a36Sopenharmony_ci &dev_attr_sma3.attr, 347262306a36Sopenharmony_ci &dev_attr_sma4.attr, 347362306a36Sopenharmony_ci &dev_attr_available_sma_inputs.attr, 347462306a36Sopenharmony_ci &dev_attr_available_sma_outputs.attr, 347562306a36Sopenharmony_ci &dev_attr_clock_status_drift.attr, 347662306a36Sopenharmony_ci &dev_attr_clock_status_offset.attr, 347762306a36Sopenharmony_ci &dev_attr_irig_b_mode.attr, 347862306a36Sopenharmony_ci &dev_attr_utc_tai_offset.attr, 347962306a36Sopenharmony_ci &dev_attr_ts_window_adjust.attr, 348062306a36Sopenharmony_ci &dev_attr_tod_correction.attr, 348162306a36Sopenharmony_ci NULL, 348262306a36Sopenharmony_ci}; 348362306a36Sopenharmony_ci 348462306a36Sopenharmony_cistatic const struct attribute_group fb_timecard_group = { 348562306a36Sopenharmony_ci .attrs = fb_timecard_attrs, 348662306a36Sopenharmony_ci}; 348762306a36Sopenharmony_ci 348862306a36Sopenharmony_cistatic const struct ocp_attr_group fb_timecard_groups[] = { 348962306a36Sopenharmony_ci { .cap = OCP_CAP_BASIC, .group = &fb_timecard_group }, 349062306a36Sopenharmony_ci { .cap = OCP_CAP_SIGNAL, .group = &fb_timecard_signal0_group }, 349162306a36Sopenharmony_ci { .cap = OCP_CAP_SIGNAL, .group = &fb_timecard_signal1_group }, 349262306a36Sopenharmony_ci { .cap = OCP_CAP_SIGNAL, .group = &fb_timecard_signal2_group }, 349362306a36Sopenharmony_ci { .cap = OCP_CAP_SIGNAL, .group = &fb_timecard_signal3_group }, 349462306a36Sopenharmony_ci { .cap = OCP_CAP_FREQ, .group = &fb_timecard_freq0_group }, 349562306a36Sopenharmony_ci { .cap = OCP_CAP_FREQ, .group = &fb_timecard_freq1_group }, 349662306a36Sopenharmony_ci { .cap = OCP_CAP_FREQ, .group = &fb_timecard_freq2_group }, 349762306a36Sopenharmony_ci { .cap = OCP_CAP_FREQ, .group = &fb_timecard_freq3_group }, 349862306a36Sopenharmony_ci { }, 349962306a36Sopenharmony_ci}; 350062306a36Sopenharmony_ci 350162306a36Sopenharmony_cistatic struct attribute *art_timecard_attrs[] = { 350262306a36Sopenharmony_ci &dev_attr_serialnum.attr, 350362306a36Sopenharmony_ci &dev_attr_clock_source.attr, 350462306a36Sopenharmony_ci &dev_attr_available_clock_sources.attr, 350562306a36Sopenharmony_ci &dev_attr_utc_tai_offset.attr, 350662306a36Sopenharmony_ci &dev_attr_ts_window_adjust.attr, 350762306a36Sopenharmony_ci &dev_attr_sma1.attr, 350862306a36Sopenharmony_ci &dev_attr_sma2.attr, 350962306a36Sopenharmony_ci &dev_attr_sma3.attr, 351062306a36Sopenharmony_ci &dev_attr_sma4.attr, 351162306a36Sopenharmony_ci &dev_attr_available_sma_inputs.attr, 351262306a36Sopenharmony_ci &dev_attr_available_sma_outputs.attr, 351362306a36Sopenharmony_ci NULL, 351462306a36Sopenharmony_ci}; 351562306a36Sopenharmony_ci 351662306a36Sopenharmony_cistatic struct bin_attribute *bin_art_timecard_attrs[] = { 351762306a36Sopenharmony_ci &bin_attr_disciplining_config, 351862306a36Sopenharmony_ci &bin_attr_temperature_table, 351962306a36Sopenharmony_ci NULL, 352062306a36Sopenharmony_ci}; 352162306a36Sopenharmony_ci 352262306a36Sopenharmony_cistatic const struct attribute_group art_timecard_group = { 352362306a36Sopenharmony_ci .attrs = art_timecard_attrs, 352462306a36Sopenharmony_ci .bin_attrs = bin_art_timecard_attrs, 352562306a36Sopenharmony_ci}; 352662306a36Sopenharmony_ci 352762306a36Sopenharmony_cistatic const struct ocp_attr_group art_timecard_groups[] = { 352862306a36Sopenharmony_ci { .cap = OCP_CAP_BASIC, .group = &art_timecard_group }, 352962306a36Sopenharmony_ci { }, 353062306a36Sopenharmony_ci}; 353162306a36Sopenharmony_ci 353262306a36Sopenharmony_cistatic void 353362306a36Sopenharmony_cigpio_input_map(char *buf, struct ptp_ocp *bp, u16 map[][2], u16 bit, 353462306a36Sopenharmony_ci const char *def) 353562306a36Sopenharmony_ci{ 353662306a36Sopenharmony_ci int i; 353762306a36Sopenharmony_ci 353862306a36Sopenharmony_ci for (i = 0; i < 4; i++) { 353962306a36Sopenharmony_ci if (bp->sma[i].mode != SMA_MODE_IN) 354062306a36Sopenharmony_ci continue; 354162306a36Sopenharmony_ci if (map[i][0] & (1 << bit)) { 354262306a36Sopenharmony_ci sprintf(buf, "sma%d", i + 1); 354362306a36Sopenharmony_ci return; 354462306a36Sopenharmony_ci } 354562306a36Sopenharmony_ci } 354662306a36Sopenharmony_ci if (!def) 354762306a36Sopenharmony_ci def = "----"; 354862306a36Sopenharmony_ci strcpy(buf, def); 354962306a36Sopenharmony_ci} 355062306a36Sopenharmony_ci 355162306a36Sopenharmony_cistatic void 355262306a36Sopenharmony_cigpio_output_map(char *buf, struct ptp_ocp *bp, u16 map[][2], u16 bit) 355362306a36Sopenharmony_ci{ 355462306a36Sopenharmony_ci char *ans = buf; 355562306a36Sopenharmony_ci int i; 355662306a36Sopenharmony_ci 355762306a36Sopenharmony_ci strcpy(ans, "----"); 355862306a36Sopenharmony_ci for (i = 0; i < 4; i++) { 355962306a36Sopenharmony_ci if (bp->sma[i].mode != SMA_MODE_OUT) 356062306a36Sopenharmony_ci continue; 356162306a36Sopenharmony_ci if (map[i][1] & (1 << bit)) 356262306a36Sopenharmony_ci ans += sprintf(ans, "sma%d ", i + 1); 356362306a36Sopenharmony_ci } 356462306a36Sopenharmony_ci} 356562306a36Sopenharmony_ci 356662306a36Sopenharmony_cistatic void 356762306a36Sopenharmony_ci_signal_summary_show(struct seq_file *s, struct ptp_ocp *bp, int nr) 356862306a36Sopenharmony_ci{ 356962306a36Sopenharmony_ci struct signal_reg __iomem *reg = bp->signal_out[nr]->mem; 357062306a36Sopenharmony_ci struct ptp_ocp_signal *signal = &bp->signal[nr]; 357162306a36Sopenharmony_ci char label[8]; 357262306a36Sopenharmony_ci bool on; 357362306a36Sopenharmony_ci u32 val; 357462306a36Sopenharmony_ci 357562306a36Sopenharmony_ci if (!signal) 357662306a36Sopenharmony_ci return; 357762306a36Sopenharmony_ci 357862306a36Sopenharmony_ci on = signal->running; 357962306a36Sopenharmony_ci sprintf(label, "GEN%d", nr + 1); 358062306a36Sopenharmony_ci seq_printf(s, "%7s: %s, period:%llu duty:%d%% phase:%llu pol:%d", 358162306a36Sopenharmony_ci label, on ? " ON" : "OFF", 358262306a36Sopenharmony_ci signal->period, signal->duty, signal->phase, 358362306a36Sopenharmony_ci signal->polarity); 358462306a36Sopenharmony_ci 358562306a36Sopenharmony_ci val = ioread32(®->enable); 358662306a36Sopenharmony_ci seq_printf(s, " [%x", val); 358762306a36Sopenharmony_ci val = ioread32(®->status); 358862306a36Sopenharmony_ci seq_printf(s, " %x]", val); 358962306a36Sopenharmony_ci 359062306a36Sopenharmony_ci seq_printf(s, " start:%llu\n", signal->start); 359162306a36Sopenharmony_ci} 359262306a36Sopenharmony_ci 359362306a36Sopenharmony_cistatic void 359462306a36Sopenharmony_ci_frequency_summary_show(struct seq_file *s, int nr, 359562306a36Sopenharmony_ci struct frequency_reg __iomem *reg) 359662306a36Sopenharmony_ci{ 359762306a36Sopenharmony_ci char label[8]; 359862306a36Sopenharmony_ci bool on; 359962306a36Sopenharmony_ci u32 val; 360062306a36Sopenharmony_ci 360162306a36Sopenharmony_ci if (!reg) 360262306a36Sopenharmony_ci return; 360362306a36Sopenharmony_ci 360462306a36Sopenharmony_ci sprintf(label, "FREQ%d", nr + 1); 360562306a36Sopenharmony_ci val = ioread32(®->ctrl); 360662306a36Sopenharmony_ci on = val & 1; 360762306a36Sopenharmony_ci val = (val >> 8) & 0xff; 360862306a36Sopenharmony_ci seq_printf(s, "%7s: %s, sec:%u", 360962306a36Sopenharmony_ci label, 361062306a36Sopenharmony_ci on ? " ON" : "OFF", 361162306a36Sopenharmony_ci val); 361262306a36Sopenharmony_ci 361362306a36Sopenharmony_ci val = ioread32(®->status); 361462306a36Sopenharmony_ci if (val & FREQ_STATUS_ERROR) 361562306a36Sopenharmony_ci seq_printf(s, ", error"); 361662306a36Sopenharmony_ci if (val & FREQ_STATUS_OVERRUN) 361762306a36Sopenharmony_ci seq_printf(s, ", overrun"); 361862306a36Sopenharmony_ci if (val & FREQ_STATUS_VALID) 361962306a36Sopenharmony_ci seq_printf(s, ", freq %lu Hz", val & FREQ_STATUS_MASK); 362062306a36Sopenharmony_ci seq_printf(s, " reg:%x\n", val); 362162306a36Sopenharmony_ci} 362262306a36Sopenharmony_ci 362362306a36Sopenharmony_cistatic int 362462306a36Sopenharmony_ciptp_ocp_summary_show(struct seq_file *s, void *data) 362562306a36Sopenharmony_ci{ 362662306a36Sopenharmony_ci struct device *dev = s->private; 362762306a36Sopenharmony_ci struct ptp_system_timestamp sts; 362862306a36Sopenharmony_ci struct ts_reg __iomem *ts_reg; 362962306a36Sopenharmony_ci char *buf, *src, *mac_src; 363062306a36Sopenharmony_ci struct timespec64 ts; 363162306a36Sopenharmony_ci struct ptp_ocp *bp; 363262306a36Sopenharmony_ci u16 sma_val[4][2]; 363362306a36Sopenharmony_ci u32 ctrl, val; 363462306a36Sopenharmony_ci bool on, map; 363562306a36Sopenharmony_ci int i; 363662306a36Sopenharmony_ci 363762306a36Sopenharmony_ci buf = (char *)__get_free_page(GFP_KERNEL); 363862306a36Sopenharmony_ci if (!buf) 363962306a36Sopenharmony_ci return -ENOMEM; 364062306a36Sopenharmony_ci 364162306a36Sopenharmony_ci bp = dev_get_drvdata(dev); 364262306a36Sopenharmony_ci 364362306a36Sopenharmony_ci seq_printf(s, "%7s: /dev/ptp%d\n", "PTP", ptp_clock_index(bp->ptp)); 364462306a36Sopenharmony_ci if (bp->gnss_port.line != -1) 364562306a36Sopenharmony_ci seq_printf(s, "%7s: /dev/ttyS%d\n", "GNSS1", 364662306a36Sopenharmony_ci bp->gnss_port.line); 364762306a36Sopenharmony_ci if (bp->gnss2_port.line != -1) 364862306a36Sopenharmony_ci seq_printf(s, "%7s: /dev/ttyS%d\n", "GNSS2", 364962306a36Sopenharmony_ci bp->gnss2_port.line); 365062306a36Sopenharmony_ci if (bp->mac_port.line != -1) 365162306a36Sopenharmony_ci seq_printf(s, "%7s: /dev/ttyS%d\n", "MAC", bp->mac_port.line); 365262306a36Sopenharmony_ci if (bp->nmea_port.line != -1) 365362306a36Sopenharmony_ci seq_printf(s, "%7s: /dev/ttyS%d\n", "NMEA", bp->nmea_port.line); 365462306a36Sopenharmony_ci 365562306a36Sopenharmony_ci memset(sma_val, 0xff, sizeof(sma_val)); 365662306a36Sopenharmony_ci if (bp->sma_map1) { 365762306a36Sopenharmony_ci u32 reg; 365862306a36Sopenharmony_ci 365962306a36Sopenharmony_ci reg = ioread32(&bp->sma_map1->gpio1); 366062306a36Sopenharmony_ci sma_val[0][0] = reg & 0xffff; 366162306a36Sopenharmony_ci sma_val[1][0] = reg >> 16; 366262306a36Sopenharmony_ci 366362306a36Sopenharmony_ci reg = ioread32(&bp->sma_map1->gpio2); 366462306a36Sopenharmony_ci sma_val[2][1] = reg & 0xffff; 366562306a36Sopenharmony_ci sma_val[3][1] = reg >> 16; 366662306a36Sopenharmony_ci 366762306a36Sopenharmony_ci reg = ioread32(&bp->sma_map2->gpio1); 366862306a36Sopenharmony_ci sma_val[2][0] = reg & 0xffff; 366962306a36Sopenharmony_ci sma_val[3][0] = reg >> 16; 367062306a36Sopenharmony_ci 367162306a36Sopenharmony_ci reg = ioread32(&bp->sma_map2->gpio2); 367262306a36Sopenharmony_ci sma_val[0][1] = reg & 0xffff; 367362306a36Sopenharmony_ci sma_val[1][1] = reg >> 16; 367462306a36Sopenharmony_ci } 367562306a36Sopenharmony_ci 367662306a36Sopenharmony_ci sma1_show(dev, NULL, buf); 367762306a36Sopenharmony_ci seq_printf(s, " sma1: %04x,%04x %s", 367862306a36Sopenharmony_ci sma_val[0][0], sma_val[0][1], buf); 367962306a36Sopenharmony_ci 368062306a36Sopenharmony_ci sma2_show(dev, NULL, buf); 368162306a36Sopenharmony_ci seq_printf(s, " sma2: %04x,%04x %s", 368262306a36Sopenharmony_ci sma_val[1][0], sma_val[1][1], buf); 368362306a36Sopenharmony_ci 368462306a36Sopenharmony_ci sma3_show(dev, NULL, buf); 368562306a36Sopenharmony_ci seq_printf(s, " sma3: %04x,%04x %s", 368662306a36Sopenharmony_ci sma_val[2][0], sma_val[2][1], buf); 368762306a36Sopenharmony_ci 368862306a36Sopenharmony_ci sma4_show(dev, NULL, buf); 368962306a36Sopenharmony_ci seq_printf(s, " sma4: %04x,%04x %s", 369062306a36Sopenharmony_ci sma_val[3][0], sma_val[3][1], buf); 369162306a36Sopenharmony_ci 369262306a36Sopenharmony_ci if (bp->ts0) { 369362306a36Sopenharmony_ci ts_reg = bp->ts0->mem; 369462306a36Sopenharmony_ci on = ioread32(&ts_reg->enable); 369562306a36Sopenharmony_ci src = "GNSS1"; 369662306a36Sopenharmony_ci seq_printf(s, "%7s: %s, src: %s\n", "TS0", 369762306a36Sopenharmony_ci on ? " ON" : "OFF", src); 369862306a36Sopenharmony_ci } 369962306a36Sopenharmony_ci 370062306a36Sopenharmony_ci if (bp->ts1) { 370162306a36Sopenharmony_ci ts_reg = bp->ts1->mem; 370262306a36Sopenharmony_ci on = ioread32(&ts_reg->enable); 370362306a36Sopenharmony_ci gpio_input_map(buf, bp, sma_val, 2, NULL); 370462306a36Sopenharmony_ci seq_printf(s, "%7s: %s, src: %s\n", "TS1", 370562306a36Sopenharmony_ci on ? " ON" : "OFF", buf); 370662306a36Sopenharmony_ci } 370762306a36Sopenharmony_ci 370862306a36Sopenharmony_ci if (bp->ts2) { 370962306a36Sopenharmony_ci ts_reg = bp->ts2->mem; 371062306a36Sopenharmony_ci on = ioread32(&ts_reg->enable); 371162306a36Sopenharmony_ci gpio_input_map(buf, bp, sma_val, 3, NULL); 371262306a36Sopenharmony_ci seq_printf(s, "%7s: %s, src: %s\n", "TS2", 371362306a36Sopenharmony_ci on ? " ON" : "OFF", buf); 371462306a36Sopenharmony_ci } 371562306a36Sopenharmony_ci 371662306a36Sopenharmony_ci if (bp->ts3) { 371762306a36Sopenharmony_ci ts_reg = bp->ts3->mem; 371862306a36Sopenharmony_ci on = ioread32(&ts_reg->enable); 371962306a36Sopenharmony_ci gpio_input_map(buf, bp, sma_val, 6, NULL); 372062306a36Sopenharmony_ci seq_printf(s, "%7s: %s, src: %s\n", "TS3", 372162306a36Sopenharmony_ci on ? " ON" : "OFF", buf); 372262306a36Sopenharmony_ci } 372362306a36Sopenharmony_ci 372462306a36Sopenharmony_ci if (bp->ts4) { 372562306a36Sopenharmony_ci ts_reg = bp->ts4->mem; 372662306a36Sopenharmony_ci on = ioread32(&ts_reg->enable); 372762306a36Sopenharmony_ci gpio_input_map(buf, bp, sma_val, 7, NULL); 372862306a36Sopenharmony_ci seq_printf(s, "%7s: %s, src: %s\n", "TS4", 372962306a36Sopenharmony_ci on ? " ON" : "OFF", buf); 373062306a36Sopenharmony_ci } 373162306a36Sopenharmony_ci 373262306a36Sopenharmony_ci if (bp->pps) { 373362306a36Sopenharmony_ci ts_reg = bp->pps->mem; 373462306a36Sopenharmony_ci src = "PHC"; 373562306a36Sopenharmony_ci on = ioread32(&ts_reg->enable); 373662306a36Sopenharmony_ci map = !!(bp->pps_req_map & OCP_REQ_TIMESTAMP); 373762306a36Sopenharmony_ci seq_printf(s, "%7s: %s, src: %s\n", "TS5", 373862306a36Sopenharmony_ci on && map ? " ON" : "OFF", src); 373962306a36Sopenharmony_ci 374062306a36Sopenharmony_ci map = !!(bp->pps_req_map & OCP_REQ_PPS); 374162306a36Sopenharmony_ci seq_printf(s, "%7s: %s, src: %s\n", "PPS", 374262306a36Sopenharmony_ci on && map ? " ON" : "OFF", src); 374362306a36Sopenharmony_ci } 374462306a36Sopenharmony_ci 374562306a36Sopenharmony_ci if (bp->fw_cap & OCP_CAP_SIGNAL) 374662306a36Sopenharmony_ci for (i = 0; i < 4; i++) 374762306a36Sopenharmony_ci _signal_summary_show(s, bp, i); 374862306a36Sopenharmony_ci 374962306a36Sopenharmony_ci if (bp->fw_cap & OCP_CAP_FREQ) 375062306a36Sopenharmony_ci for (i = 0; i < 4; i++) 375162306a36Sopenharmony_ci _frequency_summary_show(s, i, bp->freq_in[i]); 375262306a36Sopenharmony_ci 375362306a36Sopenharmony_ci if (bp->irig_out) { 375462306a36Sopenharmony_ci ctrl = ioread32(&bp->irig_out->ctrl); 375562306a36Sopenharmony_ci on = ctrl & IRIG_M_CTRL_ENABLE; 375662306a36Sopenharmony_ci val = ioread32(&bp->irig_out->status); 375762306a36Sopenharmony_ci gpio_output_map(buf, bp, sma_val, 4); 375862306a36Sopenharmony_ci seq_printf(s, "%7s: %s, error: %d, mode %d, out: %s\n", "IRIG", 375962306a36Sopenharmony_ci on ? " ON" : "OFF", val, (ctrl >> 16), buf); 376062306a36Sopenharmony_ci } 376162306a36Sopenharmony_ci 376262306a36Sopenharmony_ci if (bp->irig_in) { 376362306a36Sopenharmony_ci on = ioread32(&bp->irig_in->ctrl) & IRIG_S_CTRL_ENABLE; 376462306a36Sopenharmony_ci val = ioread32(&bp->irig_in->status); 376562306a36Sopenharmony_ci gpio_input_map(buf, bp, sma_val, 4, NULL); 376662306a36Sopenharmony_ci seq_printf(s, "%7s: %s, error: %d, src: %s\n", "IRIG in", 376762306a36Sopenharmony_ci on ? " ON" : "OFF", val, buf); 376862306a36Sopenharmony_ci } 376962306a36Sopenharmony_ci 377062306a36Sopenharmony_ci if (bp->dcf_out) { 377162306a36Sopenharmony_ci on = ioread32(&bp->dcf_out->ctrl) & DCF_M_CTRL_ENABLE; 377262306a36Sopenharmony_ci val = ioread32(&bp->dcf_out->status); 377362306a36Sopenharmony_ci gpio_output_map(buf, bp, sma_val, 5); 377462306a36Sopenharmony_ci seq_printf(s, "%7s: %s, error: %d, out: %s\n", "DCF", 377562306a36Sopenharmony_ci on ? " ON" : "OFF", val, buf); 377662306a36Sopenharmony_ci } 377762306a36Sopenharmony_ci 377862306a36Sopenharmony_ci if (bp->dcf_in) { 377962306a36Sopenharmony_ci on = ioread32(&bp->dcf_in->ctrl) & DCF_S_CTRL_ENABLE; 378062306a36Sopenharmony_ci val = ioread32(&bp->dcf_in->status); 378162306a36Sopenharmony_ci gpio_input_map(buf, bp, sma_val, 5, NULL); 378262306a36Sopenharmony_ci seq_printf(s, "%7s: %s, error: %d, src: %s\n", "DCF in", 378362306a36Sopenharmony_ci on ? " ON" : "OFF", val, buf); 378462306a36Sopenharmony_ci } 378562306a36Sopenharmony_ci 378662306a36Sopenharmony_ci if (bp->nmea_out) { 378762306a36Sopenharmony_ci on = ioread32(&bp->nmea_out->ctrl) & 1; 378862306a36Sopenharmony_ci val = ioread32(&bp->nmea_out->status); 378962306a36Sopenharmony_ci seq_printf(s, "%7s: %s, error: %d\n", "NMEA", 379062306a36Sopenharmony_ci on ? " ON" : "OFF", val); 379162306a36Sopenharmony_ci } 379262306a36Sopenharmony_ci 379362306a36Sopenharmony_ci /* compute src for PPS1, used below. */ 379462306a36Sopenharmony_ci if (bp->pps_select) { 379562306a36Sopenharmony_ci val = ioread32(&bp->pps_select->gpio1); 379662306a36Sopenharmony_ci src = &buf[80]; 379762306a36Sopenharmony_ci mac_src = "GNSS1"; 379862306a36Sopenharmony_ci if (val & 0x01) { 379962306a36Sopenharmony_ci gpio_input_map(src, bp, sma_val, 0, NULL); 380062306a36Sopenharmony_ci mac_src = src; 380162306a36Sopenharmony_ci } else if (val & 0x02) { 380262306a36Sopenharmony_ci src = "MAC"; 380362306a36Sopenharmony_ci } else if (val & 0x04) { 380462306a36Sopenharmony_ci src = "GNSS1"; 380562306a36Sopenharmony_ci } else { 380662306a36Sopenharmony_ci src = "----"; 380762306a36Sopenharmony_ci mac_src = src; 380862306a36Sopenharmony_ci } 380962306a36Sopenharmony_ci } else { 381062306a36Sopenharmony_ci src = "?"; 381162306a36Sopenharmony_ci mac_src = src; 381262306a36Sopenharmony_ci } 381362306a36Sopenharmony_ci seq_printf(s, "MAC PPS1 src: %s\n", mac_src); 381462306a36Sopenharmony_ci 381562306a36Sopenharmony_ci gpio_input_map(buf, bp, sma_val, 1, "GNSS2"); 381662306a36Sopenharmony_ci seq_printf(s, "MAC PPS2 src: %s\n", buf); 381762306a36Sopenharmony_ci 381862306a36Sopenharmony_ci /* assumes automatic switchover/selection */ 381962306a36Sopenharmony_ci val = ioread32(&bp->reg->select); 382062306a36Sopenharmony_ci switch (val >> 16) { 382162306a36Sopenharmony_ci case 0: 382262306a36Sopenharmony_ci sprintf(buf, "----"); 382362306a36Sopenharmony_ci break; 382462306a36Sopenharmony_ci case 2: 382562306a36Sopenharmony_ci sprintf(buf, "IRIG"); 382662306a36Sopenharmony_ci break; 382762306a36Sopenharmony_ci case 3: 382862306a36Sopenharmony_ci sprintf(buf, "%s via PPS1", src); 382962306a36Sopenharmony_ci break; 383062306a36Sopenharmony_ci case 6: 383162306a36Sopenharmony_ci sprintf(buf, "DCF"); 383262306a36Sopenharmony_ci break; 383362306a36Sopenharmony_ci default: 383462306a36Sopenharmony_ci strcpy(buf, "unknown"); 383562306a36Sopenharmony_ci break; 383662306a36Sopenharmony_ci } 383762306a36Sopenharmony_ci val = ioread32(&bp->reg->status); 383862306a36Sopenharmony_ci seq_printf(s, "%7s: %s, state: %s\n", "PHC src", buf, 383962306a36Sopenharmony_ci val & OCP_STATUS_IN_SYNC ? "sync" : "unsynced"); 384062306a36Sopenharmony_ci 384162306a36Sopenharmony_ci if (!ptp_ocp_gettimex(&bp->ptp_info, &ts, &sts)) { 384262306a36Sopenharmony_ci struct timespec64 sys_ts; 384362306a36Sopenharmony_ci s64 pre_ns, post_ns, ns; 384462306a36Sopenharmony_ci 384562306a36Sopenharmony_ci pre_ns = timespec64_to_ns(&sts.pre_ts); 384662306a36Sopenharmony_ci post_ns = timespec64_to_ns(&sts.post_ts); 384762306a36Sopenharmony_ci ns = (pre_ns + post_ns) / 2; 384862306a36Sopenharmony_ci ns += (s64)bp->utc_tai_offset * NSEC_PER_SEC; 384962306a36Sopenharmony_ci sys_ts = ns_to_timespec64(ns); 385062306a36Sopenharmony_ci 385162306a36Sopenharmony_ci seq_printf(s, "%7s: %lld.%ld == %ptT TAI\n", "PHC", 385262306a36Sopenharmony_ci ts.tv_sec, ts.tv_nsec, &ts); 385362306a36Sopenharmony_ci seq_printf(s, "%7s: %lld.%ld == %ptT UTC offset %d\n", "SYS", 385462306a36Sopenharmony_ci sys_ts.tv_sec, sys_ts.tv_nsec, &sys_ts, 385562306a36Sopenharmony_ci bp->utc_tai_offset); 385662306a36Sopenharmony_ci seq_printf(s, "%7s: PHC:SYS offset: %lld window: %lld\n", "", 385762306a36Sopenharmony_ci timespec64_to_ns(&ts) - ns, 385862306a36Sopenharmony_ci post_ns - pre_ns); 385962306a36Sopenharmony_ci } 386062306a36Sopenharmony_ci 386162306a36Sopenharmony_ci free_page((unsigned long)buf); 386262306a36Sopenharmony_ci return 0; 386362306a36Sopenharmony_ci} 386462306a36Sopenharmony_ciDEFINE_SHOW_ATTRIBUTE(ptp_ocp_summary); 386562306a36Sopenharmony_ci 386662306a36Sopenharmony_cistatic int 386762306a36Sopenharmony_ciptp_ocp_tod_status_show(struct seq_file *s, void *data) 386862306a36Sopenharmony_ci{ 386962306a36Sopenharmony_ci struct device *dev = s->private; 387062306a36Sopenharmony_ci struct ptp_ocp *bp; 387162306a36Sopenharmony_ci u32 val; 387262306a36Sopenharmony_ci int idx; 387362306a36Sopenharmony_ci 387462306a36Sopenharmony_ci bp = dev_get_drvdata(dev); 387562306a36Sopenharmony_ci 387662306a36Sopenharmony_ci val = ioread32(&bp->tod->ctrl); 387762306a36Sopenharmony_ci if (!(val & TOD_CTRL_ENABLE)) { 387862306a36Sopenharmony_ci seq_printf(s, "TOD Slave disabled\n"); 387962306a36Sopenharmony_ci return 0; 388062306a36Sopenharmony_ci } 388162306a36Sopenharmony_ci seq_printf(s, "TOD Slave enabled, Control Register 0x%08X\n", val); 388262306a36Sopenharmony_ci 388362306a36Sopenharmony_ci idx = val & TOD_CTRL_PROTOCOL ? 4 : 0; 388462306a36Sopenharmony_ci idx += (val >> 16) & 3; 388562306a36Sopenharmony_ci seq_printf(s, "Protocol %s\n", ptp_ocp_tod_proto_name(idx)); 388662306a36Sopenharmony_ci 388762306a36Sopenharmony_ci idx = (val >> TOD_CTRL_GNSS_SHIFT) & TOD_CTRL_GNSS_MASK; 388862306a36Sopenharmony_ci seq_printf(s, "GNSS %s\n", ptp_ocp_tod_gnss_name(idx)); 388962306a36Sopenharmony_ci 389062306a36Sopenharmony_ci val = ioread32(&bp->tod->version); 389162306a36Sopenharmony_ci seq_printf(s, "TOD Version %d.%d.%d\n", 389262306a36Sopenharmony_ci val >> 24, (val >> 16) & 0xff, val & 0xffff); 389362306a36Sopenharmony_ci 389462306a36Sopenharmony_ci val = ioread32(&bp->tod->status); 389562306a36Sopenharmony_ci seq_printf(s, "Status register: 0x%08X\n", val); 389662306a36Sopenharmony_ci 389762306a36Sopenharmony_ci val = ioread32(&bp->tod->adj_sec); 389862306a36Sopenharmony_ci idx = (val & ~INT_MAX) ? -1 : 1; 389962306a36Sopenharmony_ci idx *= (val & INT_MAX); 390062306a36Sopenharmony_ci seq_printf(s, "Correction seconds: %d\n", idx); 390162306a36Sopenharmony_ci 390262306a36Sopenharmony_ci val = ioread32(&bp->tod->utc_status); 390362306a36Sopenharmony_ci seq_printf(s, "UTC status register: 0x%08X\n", val); 390462306a36Sopenharmony_ci seq_printf(s, "UTC offset: %ld valid:%d\n", 390562306a36Sopenharmony_ci val & TOD_STATUS_UTC_MASK, val & TOD_STATUS_UTC_VALID ? 1 : 0); 390662306a36Sopenharmony_ci seq_printf(s, "Leap second info valid:%d, Leap second announce %d\n", 390762306a36Sopenharmony_ci val & TOD_STATUS_LEAP_VALID ? 1 : 0, 390862306a36Sopenharmony_ci val & TOD_STATUS_LEAP_ANNOUNCE ? 1 : 0); 390962306a36Sopenharmony_ci 391062306a36Sopenharmony_ci val = ioread32(&bp->tod->leap); 391162306a36Sopenharmony_ci seq_printf(s, "Time to next leap second (in sec): %d\n", (s32) val); 391262306a36Sopenharmony_ci 391362306a36Sopenharmony_ci return 0; 391462306a36Sopenharmony_ci} 391562306a36Sopenharmony_ciDEFINE_SHOW_ATTRIBUTE(ptp_ocp_tod_status); 391662306a36Sopenharmony_ci 391762306a36Sopenharmony_cistatic struct dentry *ptp_ocp_debugfs_root; 391862306a36Sopenharmony_ci 391962306a36Sopenharmony_cistatic void 392062306a36Sopenharmony_ciptp_ocp_debugfs_add_device(struct ptp_ocp *bp) 392162306a36Sopenharmony_ci{ 392262306a36Sopenharmony_ci struct dentry *d; 392362306a36Sopenharmony_ci 392462306a36Sopenharmony_ci d = debugfs_create_dir(dev_name(&bp->dev), ptp_ocp_debugfs_root); 392562306a36Sopenharmony_ci bp->debug_root = d; 392662306a36Sopenharmony_ci debugfs_create_file("summary", 0444, bp->debug_root, 392762306a36Sopenharmony_ci &bp->dev, &ptp_ocp_summary_fops); 392862306a36Sopenharmony_ci if (bp->tod) 392962306a36Sopenharmony_ci debugfs_create_file("tod_status", 0444, bp->debug_root, 393062306a36Sopenharmony_ci &bp->dev, &ptp_ocp_tod_status_fops); 393162306a36Sopenharmony_ci} 393262306a36Sopenharmony_ci 393362306a36Sopenharmony_cistatic void 393462306a36Sopenharmony_ciptp_ocp_debugfs_remove_device(struct ptp_ocp *bp) 393562306a36Sopenharmony_ci{ 393662306a36Sopenharmony_ci debugfs_remove_recursive(bp->debug_root); 393762306a36Sopenharmony_ci} 393862306a36Sopenharmony_ci 393962306a36Sopenharmony_cistatic void 394062306a36Sopenharmony_ciptp_ocp_debugfs_init(void) 394162306a36Sopenharmony_ci{ 394262306a36Sopenharmony_ci ptp_ocp_debugfs_root = debugfs_create_dir("timecard", NULL); 394362306a36Sopenharmony_ci} 394462306a36Sopenharmony_ci 394562306a36Sopenharmony_cistatic void 394662306a36Sopenharmony_ciptp_ocp_debugfs_fini(void) 394762306a36Sopenharmony_ci{ 394862306a36Sopenharmony_ci debugfs_remove_recursive(ptp_ocp_debugfs_root); 394962306a36Sopenharmony_ci} 395062306a36Sopenharmony_ci 395162306a36Sopenharmony_cistatic void 395262306a36Sopenharmony_ciptp_ocp_dev_release(struct device *dev) 395362306a36Sopenharmony_ci{ 395462306a36Sopenharmony_ci struct ptp_ocp *bp = dev_get_drvdata(dev); 395562306a36Sopenharmony_ci 395662306a36Sopenharmony_ci mutex_lock(&ptp_ocp_lock); 395762306a36Sopenharmony_ci idr_remove(&ptp_ocp_idr, bp->id); 395862306a36Sopenharmony_ci mutex_unlock(&ptp_ocp_lock); 395962306a36Sopenharmony_ci} 396062306a36Sopenharmony_ci 396162306a36Sopenharmony_cistatic int 396262306a36Sopenharmony_ciptp_ocp_device_init(struct ptp_ocp *bp, struct pci_dev *pdev) 396362306a36Sopenharmony_ci{ 396462306a36Sopenharmony_ci int err; 396562306a36Sopenharmony_ci 396662306a36Sopenharmony_ci mutex_lock(&ptp_ocp_lock); 396762306a36Sopenharmony_ci err = idr_alloc(&ptp_ocp_idr, bp, 0, 0, GFP_KERNEL); 396862306a36Sopenharmony_ci mutex_unlock(&ptp_ocp_lock); 396962306a36Sopenharmony_ci if (err < 0) { 397062306a36Sopenharmony_ci dev_err(&pdev->dev, "idr_alloc failed: %d\n", err); 397162306a36Sopenharmony_ci return err; 397262306a36Sopenharmony_ci } 397362306a36Sopenharmony_ci bp->id = err; 397462306a36Sopenharmony_ci 397562306a36Sopenharmony_ci bp->ptp_info = ptp_ocp_clock_info; 397662306a36Sopenharmony_ci spin_lock_init(&bp->lock); 397762306a36Sopenharmony_ci bp->gnss_port.line = -1; 397862306a36Sopenharmony_ci bp->gnss2_port.line = -1; 397962306a36Sopenharmony_ci bp->mac_port.line = -1; 398062306a36Sopenharmony_ci bp->nmea_port.line = -1; 398162306a36Sopenharmony_ci bp->pdev = pdev; 398262306a36Sopenharmony_ci 398362306a36Sopenharmony_ci device_initialize(&bp->dev); 398462306a36Sopenharmony_ci dev_set_name(&bp->dev, "ocp%d", bp->id); 398562306a36Sopenharmony_ci bp->dev.class = &timecard_class; 398662306a36Sopenharmony_ci bp->dev.parent = &pdev->dev; 398762306a36Sopenharmony_ci bp->dev.release = ptp_ocp_dev_release; 398862306a36Sopenharmony_ci dev_set_drvdata(&bp->dev, bp); 398962306a36Sopenharmony_ci 399062306a36Sopenharmony_ci err = device_add(&bp->dev); 399162306a36Sopenharmony_ci if (err) { 399262306a36Sopenharmony_ci dev_err(&bp->dev, "device add failed: %d\n", err); 399362306a36Sopenharmony_ci goto out; 399462306a36Sopenharmony_ci } 399562306a36Sopenharmony_ci 399662306a36Sopenharmony_ci pci_set_drvdata(pdev, bp); 399762306a36Sopenharmony_ci 399862306a36Sopenharmony_ci return 0; 399962306a36Sopenharmony_ci 400062306a36Sopenharmony_ciout: 400162306a36Sopenharmony_ci put_device(&bp->dev); 400262306a36Sopenharmony_ci return err; 400362306a36Sopenharmony_ci} 400462306a36Sopenharmony_ci 400562306a36Sopenharmony_cistatic void 400662306a36Sopenharmony_ciptp_ocp_symlink(struct ptp_ocp *bp, struct device *child, const char *link) 400762306a36Sopenharmony_ci{ 400862306a36Sopenharmony_ci struct device *dev = &bp->dev; 400962306a36Sopenharmony_ci 401062306a36Sopenharmony_ci if (sysfs_create_link(&dev->kobj, &child->kobj, link)) 401162306a36Sopenharmony_ci dev_err(dev, "%s symlink failed\n", link); 401262306a36Sopenharmony_ci} 401362306a36Sopenharmony_ci 401462306a36Sopenharmony_cistatic void 401562306a36Sopenharmony_ciptp_ocp_link_child(struct ptp_ocp *bp, const char *name, const char *link) 401662306a36Sopenharmony_ci{ 401762306a36Sopenharmony_ci struct device *dev, *child; 401862306a36Sopenharmony_ci 401962306a36Sopenharmony_ci dev = &bp->pdev->dev; 402062306a36Sopenharmony_ci 402162306a36Sopenharmony_ci child = device_find_child_by_name(dev, name); 402262306a36Sopenharmony_ci if (!child) { 402362306a36Sopenharmony_ci dev_err(dev, "Could not find device %s\n", name); 402462306a36Sopenharmony_ci return; 402562306a36Sopenharmony_ci } 402662306a36Sopenharmony_ci 402762306a36Sopenharmony_ci ptp_ocp_symlink(bp, child, link); 402862306a36Sopenharmony_ci put_device(child); 402962306a36Sopenharmony_ci} 403062306a36Sopenharmony_ci 403162306a36Sopenharmony_cistatic int 403262306a36Sopenharmony_ciptp_ocp_complete(struct ptp_ocp *bp) 403362306a36Sopenharmony_ci{ 403462306a36Sopenharmony_ci struct pps_device *pps; 403562306a36Sopenharmony_ci char buf[32]; 403662306a36Sopenharmony_ci 403762306a36Sopenharmony_ci if (bp->gnss_port.line != -1) { 403862306a36Sopenharmony_ci sprintf(buf, "ttyS%d", bp->gnss_port.line); 403962306a36Sopenharmony_ci ptp_ocp_link_child(bp, buf, "ttyGNSS"); 404062306a36Sopenharmony_ci } 404162306a36Sopenharmony_ci if (bp->gnss2_port.line != -1) { 404262306a36Sopenharmony_ci sprintf(buf, "ttyS%d", bp->gnss2_port.line); 404362306a36Sopenharmony_ci ptp_ocp_link_child(bp, buf, "ttyGNSS2"); 404462306a36Sopenharmony_ci } 404562306a36Sopenharmony_ci if (bp->mac_port.line != -1) { 404662306a36Sopenharmony_ci sprintf(buf, "ttyS%d", bp->mac_port.line); 404762306a36Sopenharmony_ci ptp_ocp_link_child(bp, buf, "ttyMAC"); 404862306a36Sopenharmony_ci } 404962306a36Sopenharmony_ci if (bp->nmea_port.line != -1) { 405062306a36Sopenharmony_ci sprintf(buf, "ttyS%d", bp->nmea_port.line); 405162306a36Sopenharmony_ci ptp_ocp_link_child(bp, buf, "ttyNMEA"); 405262306a36Sopenharmony_ci } 405362306a36Sopenharmony_ci sprintf(buf, "ptp%d", ptp_clock_index(bp->ptp)); 405462306a36Sopenharmony_ci ptp_ocp_link_child(bp, buf, "ptp"); 405562306a36Sopenharmony_ci 405662306a36Sopenharmony_ci pps = pps_lookup_dev(bp->ptp); 405762306a36Sopenharmony_ci if (pps) 405862306a36Sopenharmony_ci ptp_ocp_symlink(bp, pps->dev, "pps"); 405962306a36Sopenharmony_ci 406062306a36Sopenharmony_ci ptp_ocp_debugfs_add_device(bp); 406162306a36Sopenharmony_ci 406262306a36Sopenharmony_ci return 0; 406362306a36Sopenharmony_ci} 406462306a36Sopenharmony_ci 406562306a36Sopenharmony_cistatic void 406662306a36Sopenharmony_ciptp_ocp_phc_info(struct ptp_ocp *bp) 406762306a36Sopenharmony_ci{ 406862306a36Sopenharmony_ci struct timespec64 ts; 406962306a36Sopenharmony_ci u32 version, select; 407062306a36Sopenharmony_ci bool sync; 407162306a36Sopenharmony_ci 407262306a36Sopenharmony_ci version = ioread32(&bp->reg->version); 407362306a36Sopenharmony_ci select = ioread32(&bp->reg->select); 407462306a36Sopenharmony_ci dev_info(&bp->pdev->dev, "Version %d.%d.%d, clock %s, device ptp%d\n", 407562306a36Sopenharmony_ci version >> 24, (version >> 16) & 0xff, version & 0xffff, 407662306a36Sopenharmony_ci ptp_ocp_select_name_from_val(ptp_ocp_clock, select >> 16), 407762306a36Sopenharmony_ci ptp_clock_index(bp->ptp)); 407862306a36Sopenharmony_ci 407962306a36Sopenharmony_ci sync = ioread32(&bp->reg->status) & OCP_STATUS_IN_SYNC; 408062306a36Sopenharmony_ci if (!ptp_ocp_gettimex(&bp->ptp_info, &ts, NULL)) 408162306a36Sopenharmony_ci dev_info(&bp->pdev->dev, "Time: %lld.%ld, %s\n", 408262306a36Sopenharmony_ci ts.tv_sec, ts.tv_nsec, 408362306a36Sopenharmony_ci sync ? "in-sync" : "UNSYNCED"); 408462306a36Sopenharmony_ci} 408562306a36Sopenharmony_ci 408662306a36Sopenharmony_cistatic void 408762306a36Sopenharmony_ciptp_ocp_serial_info(struct device *dev, const char *name, int port, int baud) 408862306a36Sopenharmony_ci{ 408962306a36Sopenharmony_ci if (port != -1) 409062306a36Sopenharmony_ci dev_info(dev, "%5s: /dev/ttyS%-2d @ %6d\n", name, port, baud); 409162306a36Sopenharmony_ci} 409262306a36Sopenharmony_ci 409362306a36Sopenharmony_cistatic void 409462306a36Sopenharmony_ciptp_ocp_info(struct ptp_ocp *bp) 409562306a36Sopenharmony_ci{ 409662306a36Sopenharmony_ci static int nmea_baud[] = { 409762306a36Sopenharmony_ci 1200, 2400, 4800, 9600, 19200, 38400, 409862306a36Sopenharmony_ci 57600, 115200, 230400, 460800, 921600, 409962306a36Sopenharmony_ci 1000000, 2000000 410062306a36Sopenharmony_ci }; 410162306a36Sopenharmony_ci struct device *dev = &bp->pdev->dev; 410262306a36Sopenharmony_ci u32 reg; 410362306a36Sopenharmony_ci 410462306a36Sopenharmony_ci ptp_ocp_phc_info(bp); 410562306a36Sopenharmony_ci 410662306a36Sopenharmony_ci ptp_ocp_serial_info(dev, "GNSS", bp->gnss_port.line, 410762306a36Sopenharmony_ci bp->gnss_port.baud); 410862306a36Sopenharmony_ci ptp_ocp_serial_info(dev, "GNSS2", bp->gnss2_port.line, 410962306a36Sopenharmony_ci bp->gnss2_port.baud); 411062306a36Sopenharmony_ci ptp_ocp_serial_info(dev, "MAC", bp->mac_port.line, bp->mac_port.baud); 411162306a36Sopenharmony_ci if (bp->nmea_out && bp->nmea_port.line != -1) { 411262306a36Sopenharmony_ci bp->nmea_port.baud = -1; 411362306a36Sopenharmony_ci 411462306a36Sopenharmony_ci reg = ioread32(&bp->nmea_out->uart_baud); 411562306a36Sopenharmony_ci if (reg < ARRAY_SIZE(nmea_baud)) 411662306a36Sopenharmony_ci bp->nmea_port.baud = nmea_baud[reg]; 411762306a36Sopenharmony_ci 411862306a36Sopenharmony_ci ptp_ocp_serial_info(dev, "NMEA", bp->nmea_port.line, 411962306a36Sopenharmony_ci bp->nmea_port.baud); 412062306a36Sopenharmony_ci } 412162306a36Sopenharmony_ci} 412262306a36Sopenharmony_ci 412362306a36Sopenharmony_cistatic void 412462306a36Sopenharmony_ciptp_ocp_detach_sysfs(struct ptp_ocp *bp) 412562306a36Sopenharmony_ci{ 412662306a36Sopenharmony_ci struct device *dev = &bp->dev; 412762306a36Sopenharmony_ci 412862306a36Sopenharmony_ci sysfs_remove_link(&dev->kobj, "ttyGNSS"); 412962306a36Sopenharmony_ci sysfs_remove_link(&dev->kobj, "ttyGNSS2"); 413062306a36Sopenharmony_ci sysfs_remove_link(&dev->kobj, "ttyMAC"); 413162306a36Sopenharmony_ci sysfs_remove_link(&dev->kobj, "ptp"); 413262306a36Sopenharmony_ci sysfs_remove_link(&dev->kobj, "pps"); 413362306a36Sopenharmony_ci} 413462306a36Sopenharmony_ci 413562306a36Sopenharmony_cistatic void 413662306a36Sopenharmony_ciptp_ocp_detach(struct ptp_ocp *bp) 413762306a36Sopenharmony_ci{ 413862306a36Sopenharmony_ci int i; 413962306a36Sopenharmony_ci 414062306a36Sopenharmony_ci ptp_ocp_debugfs_remove_device(bp); 414162306a36Sopenharmony_ci ptp_ocp_detach_sysfs(bp); 414262306a36Sopenharmony_ci ptp_ocp_attr_group_del(bp); 414362306a36Sopenharmony_ci if (timer_pending(&bp->watchdog)) 414462306a36Sopenharmony_ci del_timer_sync(&bp->watchdog); 414562306a36Sopenharmony_ci if (bp->ts0) 414662306a36Sopenharmony_ci ptp_ocp_unregister_ext(bp->ts0); 414762306a36Sopenharmony_ci if (bp->ts1) 414862306a36Sopenharmony_ci ptp_ocp_unregister_ext(bp->ts1); 414962306a36Sopenharmony_ci if (bp->ts2) 415062306a36Sopenharmony_ci ptp_ocp_unregister_ext(bp->ts2); 415162306a36Sopenharmony_ci if (bp->ts3) 415262306a36Sopenharmony_ci ptp_ocp_unregister_ext(bp->ts3); 415362306a36Sopenharmony_ci if (bp->ts4) 415462306a36Sopenharmony_ci ptp_ocp_unregister_ext(bp->ts4); 415562306a36Sopenharmony_ci if (bp->pps) 415662306a36Sopenharmony_ci ptp_ocp_unregister_ext(bp->pps); 415762306a36Sopenharmony_ci for (i = 0; i < 4; i++) 415862306a36Sopenharmony_ci if (bp->signal_out[i]) 415962306a36Sopenharmony_ci ptp_ocp_unregister_ext(bp->signal_out[i]); 416062306a36Sopenharmony_ci if (bp->gnss_port.line != -1) 416162306a36Sopenharmony_ci serial8250_unregister_port(bp->gnss_port.line); 416262306a36Sopenharmony_ci if (bp->gnss2_port.line != -1) 416362306a36Sopenharmony_ci serial8250_unregister_port(bp->gnss2_port.line); 416462306a36Sopenharmony_ci if (bp->mac_port.line != -1) 416562306a36Sopenharmony_ci serial8250_unregister_port(bp->mac_port.line); 416662306a36Sopenharmony_ci if (bp->nmea_port.line != -1) 416762306a36Sopenharmony_ci serial8250_unregister_port(bp->nmea_port.line); 416862306a36Sopenharmony_ci platform_device_unregister(bp->spi_flash); 416962306a36Sopenharmony_ci platform_device_unregister(bp->i2c_ctrl); 417062306a36Sopenharmony_ci if (bp->i2c_clk) 417162306a36Sopenharmony_ci clk_hw_unregister_fixed_rate(bp->i2c_clk); 417262306a36Sopenharmony_ci if (bp->n_irqs) 417362306a36Sopenharmony_ci pci_free_irq_vectors(bp->pdev); 417462306a36Sopenharmony_ci if (bp->ptp) 417562306a36Sopenharmony_ci ptp_clock_unregister(bp->ptp); 417662306a36Sopenharmony_ci kfree(bp->ptp_info.pin_config); 417762306a36Sopenharmony_ci device_unregister(&bp->dev); 417862306a36Sopenharmony_ci} 417962306a36Sopenharmony_ci 418062306a36Sopenharmony_cistatic int 418162306a36Sopenharmony_ciptp_ocp_probe(struct pci_dev *pdev, const struct pci_device_id *id) 418262306a36Sopenharmony_ci{ 418362306a36Sopenharmony_ci struct devlink *devlink; 418462306a36Sopenharmony_ci struct ptp_ocp *bp; 418562306a36Sopenharmony_ci int err; 418662306a36Sopenharmony_ci 418762306a36Sopenharmony_ci devlink = devlink_alloc(&ptp_ocp_devlink_ops, sizeof(*bp), &pdev->dev); 418862306a36Sopenharmony_ci if (!devlink) { 418962306a36Sopenharmony_ci dev_err(&pdev->dev, "devlink_alloc failed\n"); 419062306a36Sopenharmony_ci return -ENOMEM; 419162306a36Sopenharmony_ci } 419262306a36Sopenharmony_ci 419362306a36Sopenharmony_ci err = pci_enable_device(pdev); 419462306a36Sopenharmony_ci if (err) { 419562306a36Sopenharmony_ci dev_err(&pdev->dev, "pci_enable_device\n"); 419662306a36Sopenharmony_ci goto out_free; 419762306a36Sopenharmony_ci } 419862306a36Sopenharmony_ci 419962306a36Sopenharmony_ci bp = devlink_priv(devlink); 420062306a36Sopenharmony_ci err = ptp_ocp_device_init(bp, pdev); 420162306a36Sopenharmony_ci if (err) 420262306a36Sopenharmony_ci goto out_disable; 420362306a36Sopenharmony_ci 420462306a36Sopenharmony_ci /* compat mode. 420562306a36Sopenharmony_ci * Older FPGA firmware only returns 2 irq's. 420662306a36Sopenharmony_ci * allow this - if not all of the IRQ's are returned, skip the 420762306a36Sopenharmony_ci * extra devices and just register the clock. 420862306a36Sopenharmony_ci */ 420962306a36Sopenharmony_ci err = pci_alloc_irq_vectors(pdev, 1, 17, PCI_IRQ_MSI | PCI_IRQ_MSIX); 421062306a36Sopenharmony_ci if (err < 0) { 421162306a36Sopenharmony_ci dev_err(&pdev->dev, "alloc_irq_vectors err: %d\n", err); 421262306a36Sopenharmony_ci goto out; 421362306a36Sopenharmony_ci } 421462306a36Sopenharmony_ci bp->n_irqs = err; 421562306a36Sopenharmony_ci pci_set_master(pdev); 421662306a36Sopenharmony_ci 421762306a36Sopenharmony_ci err = ptp_ocp_register_resources(bp, id->driver_data); 421862306a36Sopenharmony_ci if (err) 421962306a36Sopenharmony_ci goto out; 422062306a36Sopenharmony_ci 422162306a36Sopenharmony_ci bp->ptp = ptp_clock_register(&bp->ptp_info, &pdev->dev); 422262306a36Sopenharmony_ci if (IS_ERR(bp->ptp)) { 422362306a36Sopenharmony_ci err = PTR_ERR(bp->ptp); 422462306a36Sopenharmony_ci dev_err(&pdev->dev, "ptp_clock_register: %d\n", err); 422562306a36Sopenharmony_ci bp->ptp = NULL; 422662306a36Sopenharmony_ci goto out; 422762306a36Sopenharmony_ci } 422862306a36Sopenharmony_ci 422962306a36Sopenharmony_ci err = ptp_ocp_complete(bp); 423062306a36Sopenharmony_ci if (err) 423162306a36Sopenharmony_ci goto out; 423262306a36Sopenharmony_ci 423362306a36Sopenharmony_ci ptp_ocp_info(bp); 423462306a36Sopenharmony_ci devlink_register(devlink); 423562306a36Sopenharmony_ci return 0; 423662306a36Sopenharmony_ci 423762306a36Sopenharmony_ciout: 423862306a36Sopenharmony_ci ptp_ocp_detach(bp); 423962306a36Sopenharmony_ciout_disable: 424062306a36Sopenharmony_ci pci_disable_device(pdev); 424162306a36Sopenharmony_ciout_free: 424262306a36Sopenharmony_ci devlink_free(devlink); 424362306a36Sopenharmony_ci return err; 424462306a36Sopenharmony_ci} 424562306a36Sopenharmony_ci 424662306a36Sopenharmony_cistatic void 424762306a36Sopenharmony_ciptp_ocp_remove(struct pci_dev *pdev) 424862306a36Sopenharmony_ci{ 424962306a36Sopenharmony_ci struct ptp_ocp *bp = pci_get_drvdata(pdev); 425062306a36Sopenharmony_ci struct devlink *devlink = priv_to_devlink(bp); 425162306a36Sopenharmony_ci 425262306a36Sopenharmony_ci devlink_unregister(devlink); 425362306a36Sopenharmony_ci ptp_ocp_detach(bp); 425462306a36Sopenharmony_ci pci_disable_device(pdev); 425562306a36Sopenharmony_ci 425662306a36Sopenharmony_ci devlink_free(devlink); 425762306a36Sopenharmony_ci} 425862306a36Sopenharmony_ci 425962306a36Sopenharmony_cistatic struct pci_driver ptp_ocp_driver = { 426062306a36Sopenharmony_ci .name = KBUILD_MODNAME, 426162306a36Sopenharmony_ci .id_table = ptp_ocp_pcidev_id, 426262306a36Sopenharmony_ci .probe = ptp_ocp_probe, 426362306a36Sopenharmony_ci .remove = ptp_ocp_remove, 426462306a36Sopenharmony_ci}; 426562306a36Sopenharmony_ci 426662306a36Sopenharmony_cistatic int 426762306a36Sopenharmony_ciptp_ocp_i2c_notifier_call(struct notifier_block *nb, 426862306a36Sopenharmony_ci unsigned long action, void *data) 426962306a36Sopenharmony_ci{ 427062306a36Sopenharmony_ci struct device *dev, *child = data; 427162306a36Sopenharmony_ci struct ptp_ocp *bp; 427262306a36Sopenharmony_ci bool add; 427362306a36Sopenharmony_ci 427462306a36Sopenharmony_ci switch (action) { 427562306a36Sopenharmony_ci case BUS_NOTIFY_ADD_DEVICE: 427662306a36Sopenharmony_ci case BUS_NOTIFY_DEL_DEVICE: 427762306a36Sopenharmony_ci add = action == BUS_NOTIFY_ADD_DEVICE; 427862306a36Sopenharmony_ci break; 427962306a36Sopenharmony_ci default: 428062306a36Sopenharmony_ci return 0; 428162306a36Sopenharmony_ci } 428262306a36Sopenharmony_ci 428362306a36Sopenharmony_ci if (!i2c_verify_adapter(child)) 428462306a36Sopenharmony_ci return 0; 428562306a36Sopenharmony_ci 428662306a36Sopenharmony_ci dev = child; 428762306a36Sopenharmony_ci while ((dev = dev->parent)) 428862306a36Sopenharmony_ci if (dev->driver && !strcmp(dev->driver->name, KBUILD_MODNAME)) 428962306a36Sopenharmony_ci goto found; 429062306a36Sopenharmony_ci return 0; 429162306a36Sopenharmony_ci 429262306a36Sopenharmony_cifound: 429362306a36Sopenharmony_ci bp = dev_get_drvdata(dev); 429462306a36Sopenharmony_ci if (add) 429562306a36Sopenharmony_ci ptp_ocp_symlink(bp, child, "i2c"); 429662306a36Sopenharmony_ci else 429762306a36Sopenharmony_ci sysfs_remove_link(&bp->dev.kobj, "i2c"); 429862306a36Sopenharmony_ci 429962306a36Sopenharmony_ci return 0; 430062306a36Sopenharmony_ci} 430162306a36Sopenharmony_ci 430262306a36Sopenharmony_cistatic struct notifier_block ptp_ocp_i2c_notifier = { 430362306a36Sopenharmony_ci .notifier_call = ptp_ocp_i2c_notifier_call, 430462306a36Sopenharmony_ci}; 430562306a36Sopenharmony_ci 430662306a36Sopenharmony_cistatic int __init 430762306a36Sopenharmony_ciptp_ocp_init(void) 430862306a36Sopenharmony_ci{ 430962306a36Sopenharmony_ci const char *what; 431062306a36Sopenharmony_ci int err; 431162306a36Sopenharmony_ci 431262306a36Sopenharmony_ci ptp_ocp_debugfs_init(); 431362306a36Sopenharmony_ci 431462306a36Sopenharmony_ci what = "timecard class"; 431562306a36Sopenharmony_ci err = class_register(&timecard_class); 431662306a36Sopenharmony_ci if (err) 431762306a36Sopenharmony_ci goto out; 431862306a36Sopenharmony_ci 431962306a36Sopenharmony_ci what = "i2c notifier"; 432062306a36Sopenharmony_ci err = bus_register_notifier(&i2c_bus_type, &ptp_ocp_i2c_notifier); 432162306a36Sopenharmony_ci if (err) 432262306a36Sopenharmony_ci goto out_notifier; 432362306a36Sopenharmony_ci 432462306a36Sopenharmony_ci what = "ptp_ocp driver"; 432562306a36Sopenharmony_ci err = pci_register_driver(&ptp_ocp_driver); 432662306a36Sopenharmony_ci if (err) 432762306a36Sopenharmony_ci goto out_register; 432862306a36Sopenharmony_ci 432962306a36Sopenharmony_ci return 0; 433062306a36Sopenharmony_ci 433162306a36Sopenharmony_ciout_register: 433262306a36Sopenharmony_ci bus_unregister_notifier(&i2c_bus_type, &ptp_ocp_i2c_notifier); 433362306a36Sopenharmony_ciout_notifier: 433462306a36Sopenharmony_ci class_unregister(&timecard_class); 433562306a36Sopenharmony_ciout: 433662306a36Sopenharmony_ci ptp_ocp_debugfs_fini(); 433762306a36Sopenharmony_ci pr_err(KBUILD_MODNAME ": failed to register %s: %d\n", what, err); 433862306a36Sopenharmony_ci return err; 433962306a36Sopenharmony_ci} 434062306a36Sopenharmony_ci 434162306a36Sopenharmony_cistatic void __exit 434262306a36Sopenharmony_ciptp_ocp_fini(void) 434362306a36Sopenharmony_ci{ 434462306a36Sopenharmony_ci bus_unregister_notifier(&i2c_bus_type, &ptp_ocp_i2c_notifier); 434562306a36Sopenharmony_ci pci_unregister_driver(&ptp_ocp_driver); 434662306a36Sopenharmony_ci class_unregister(&timecard_class); 434762306a36Sopenharmony_ci ptp_ocp_debugfs_fini(); 434862306a36Sopenharmony_ci} 434962306a36Sopenharmony_ci 435062306a36Sopenharmony_cimodule_init(ptp_ocp_init); 435162306a36Sopenharmony_cimodule_exit(ptp_ocp_fini); 435262306a36Sopenharmony_ci 435362306a36Sopenharmony_ciMODULE_DESCRIPTION("OpenCompute TimeCard driver"); 435462306a36Sopenharmony_ciMODULE_LICENSE("GPL v2"); 4355