162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Device driver for the Cuda and Egret system controllers found on PowerMacs 462306a36Sopenharmony_ci * and 68k Macs. 562306a36Sopenharmony_ci * 662306a36Sopenharmony_ci * The Cuda or Egret is a 6805 microcontroller interfaced to the 6522 VIA. 762306a36Sopenharmony_ci * This MCU controls system power, Parameter RAM, Real Time Clock and the 862306a36Sopenharmony_ci * Apple Desktop Bus (ADB) that connects to the keyboard and mouse. 962306a36Sopenharmony_ci * 1062306a36Sopenharmony_ci * Copyright (C) 1996 Paul Mackerras. 1162306a36Sopenharmony_ci */ 1262306a36Sopenharmony_ci#include <linux/stdarg.h> 1362306a36Sopenharmony_ci#include <linux/types.h> 1462306a36Sopenharmony_ci#include <linux/errno.h> 1562306a36Sopenharmony_ci#include <linux/kernel.h> 1662306a36Sopenharmony_ci#include <linux/delay.h> 1762306a36Sopenharmony_ci#include <linux/adb.h> 1862306a36Sopenharmony_ci#include <linux/cuda.h> 1962306a36Sopenharmony_ci#include <linux/spinlock.h> 2062306a36Sopenharmony_ci#include <linux/interrupt.h> 2162306a36Sopenharmony_ci#include <linux/of_address.h> 2262306a36Sopenharmony_ci#include <linux/of_irq.h> 2362306a36Sopenharmony_ci 2462306a36Sopenharmony_ci#ifdef CONFIG_PPC 2562306a36Sopenharmony_ci#include <asm/machdep.h> 2662306a36Sopenharmony_ci#include <asm/pmac_feature.h> 2762306a36Sopenharmony_ci#else 2862306a36Sopenharmony_ci#include <asm/macintosh.h> 2962306a36Sopenharmony_ci#include <asm/macints.h> 3062306a36Sopenharmony_ci#include <asm/mac_via.h> 3162306a36Sopenharmony_ci#endif 3262306a36Sopenharmony_ci#include <asm/io.h> 3362306a36Sopenharmony_ci#include <linux/init.h> 3462306a36Sopenharmony_ci 3562306a36Sopenharmony_cistatic volatile unsigned char __iomem *via; 3662306a36Sopenharmony_cistatic DEFINE_SPINLOCK(cuda_lock); 3762306a36Sopenharmony_ci 3862306a36Sopenharmony_ci/* VIA registers - spaced 0x200 bytes apart */ 3962306a36Sopenharmony_ci#define RS 0x200 /* skip between registers */ 4062306a36Sopenharmony_ci#define B 0 /* B-side data */ 4162306a36Sopenharmony_ci#define A RS /* A-side data */ 4262306a36Sopenharmony_ci#define DIRB (2*RS) /* B-side direction (1=output) */ 4362306a36Sopenharmony_ci#define DIRA (3*RS) /* A-side direction (1=output) */ 4462306a36Sopenharmony_ci#define T1CL (4*RS) /* Timer 1 ctr/latch (low 8 bits) */ 4562306a36Sopenharmony_ci#define T1CH (5*RS) /* Timer 1 counter (high 8 bits) */ 4662306a36Sopenharmony_ci#define T1LL (6*RS) /* Timer 1 latch (low 8 bits) */ 4762306a36Sopenharmony_ci#define T1LH (7*RS) /* Timer 1 latch (high 8 bits) */ 4862306a36Sopenharmony_ci#define T2CL (8*RS) /* Timer 2 ctr/latch (low 8 bits) */ 4962306a36Sopenharmony_ci#define T2CH (9*RS) /* Timer 2 counter (high 8 bits) */ 5062306a36Sopenharmony_ci#define SR (10*RS) /* Shift register */ 5162306a36Sopenharmony_ci#define ACR (11*RS) /* Auxiliary control register */ 5262306a36Sopenharmony_ci#define PCR (12*RS) /* Peripheral control register */ 5362306a36Sopenharmony_ci#define IFR (13*RS) /* Interrupt flag register */ 5462306a36Sopenharmony_ci#define IER (14*RS) /* Interrupt enable register */ 5562306a36Sopenharmony_ci#define ANH (15*RS) /* A-side data, no handshake */ 5662306a36Sopenharmony_ci 5762306a36Sopenharmony_ci/* 5862306a36Sopenharmony_ci * When the Cuda design replaced the Egret, some signal names and 5962306a36Sopenharmony_ci * logic sense changed. They all serve the same purposes, however. 6062306a36Sopenharmony_ci * 6162306a36Sopenharmony_ci * VIA pin | Egret pin 6262306a36Sopenharmony_ci * ----------------+------------------------------------------ 6362306a36Sopenharmony_ci * PB3 (input) | Transceiver session (active low) 6462306a36Sopenharmony_ci * PB4 (output) | VIA full (active high) 6562306a36Sopenharmony_ci * PB5 (output) | System session (active high) 6662306a36Sopenharmony_ci * 6762306a36Sopenharmony_ci * VIA pin | Cuda pin 6862306a36Sopenharmony_ci * ----------------+------------------------------------------ 6962306a36Sopenharmony_ci * PB3 (input) | Transfer request (active low) 7062306a36Sopenharmony_ci * PB4 (output) | Byte acknowledge (active low) 7162306a36Sopenharmony_ci * PB5 (output) | Transfer in progress (active low) 7262306a36Sopenharmony_ci */ 7362306a36Sopenharmony_ci 7462306a36Sopenharmony_ci/* Bits in Port B data register */ 7562306a36Sopenharmony_ci#define TREQ 0x08 /* Transfer request */ 7662306a36Sopenharmony_ci#define TACK 0x10 /* Transfer acknowledge */ 7762306a36Sopenharmony_ci#define TIP 0x20 /* Transfer in progress */ 7862306a36Sopenharmony_ci 7962306a36Sopenharmony_ci/* Bits in ACR */ 8062306a36Sopenharmony_ci#define SR_CTRL 0x1c /* Shift register control bits */ 8162306a36Sopenharmony_ci#define SR_EXT 0x0c /* Shift on external clock */ 8262306a36Sopenharmony_ci#define SR_OUT 0x10 /* Shift out if 1 */ 8362306a36Sopenharmony_ci 8462306a36Sopenharmony_ci/* Bits in IFR and IER */ 8562306a36Sopenharmony_ci#define IER_SET 0x80 /* set bits in IER */ 8662306a36Sopenharmony_ci#define IER_CLR 0 /* clear bits in IER */ 8762306a36Sopenharmony_ci#define SR_INT 0x04 /* Shift register full/empty */ 8862306a36Sopenharmony_ci 8962306a36Sopenharmony_ci/* Duration of byte acknowledgement pulse (us) */ 9062306a36Sopenharmony_ci#define EGRET_TACK_ASSERTED_DELAY 300 9162306a36Sopenharmony_ci#define EGRET_TACK_NEGATED_DELAY 400 9262306a36Sopenharmony_ci 9362306a36Sopenharmony_ci/* Interval from interrupt to start of session (us) */ 9462306a36Sopenharmony_ci#define EGRET_SESSION_DELAY 450 9562306a36Sopenharmony_ci 9662306a36Sopenharmony_ci#ifdef CONFIG_PPC 9762306a36Sopenharmony_ci#define mcu_is_egret false 9862306a36Sopenharmony_ci#else 9962306a36Sopenharmony_cistatic bool mcu_is_egret; 10062306a36Sopenharmony_ci#endif 10162306a36Sopenharmony_ci 10262306a36Sopenharmony_cistatic inline bool TREQ_asserted(u8 portb) 10362306a36Sopenharmony_ci{ 10462306a36Sopenharmony_ci return !(portb & TREQ); 10562306a36Sopenharmony_ci} 10662306a36Sopenharmony_ci 10762306a36Sopenharmony_cistatic inline void assert_TIP(void) 10862306a36Sopenharmony_ci{ 10962306a36Sopenharmony_ci if (mcu_is_egret) { 11062306a36Sopenharmony_ci udelay(EGRET_SESSION_DELAY); 11162306a36Sopenharmony_ci out_8(&via[B], in_8(&via[B]) | TIP); 11262306a36Sopenharmony_ci } else 11362306a36Sopenharmony_ci out_8(&via[B], in_8(&via[B]) & ~TIP); 11462306a36Sopenharmony_ci} 11562306a36Sopenharmony_ci 11662306a36Sopenharmony_cistatic inline void assert_TIP_and_TACK(void) 11762306a36Sopenharmony_ci{ 11862306a36Sopenharmony_ci if (mcu_is_egret) { 11962306a36Sopenharmony_ci udelay(EGRET_SESSION_DELAY); 12062306a36Sopenharmony_ci out_8(&via[B], in_8(&via[B]) | TIP | TACK); 12162306a36Sopenharmony_ci } else 12262306a36Sopenharmony_ci out_8(&via[B], in_8(&via[B]) & ~(TIP | TACK)); 12362306a36Sopenharmony_ci} 12462306a36Sopenharmony_ci 12562306a36Sopenharmony_cistatic inline void assert_TACK(void) 12662306a36Sopenharmony_ci{ 12762306a36Sopenharmony_ci if (mcu_is_egret) { 12862306a36Sopenharmony_ci udelay(EGRET_TACK_NEGATED_DELAY); 12962306a36Sopenharmony_ci out_8(&via[B], in_8(&via[B]) | TACK); 13062306a36Sopenharmony_ci } else 13162306a36Sopenharmony_ci out_8(&via[B], in_8(&via[B]) & ~TACK); 13262306a36Sopenharmony_ci} 13362306a36Sopenharmony_ci 13462306a36Sopenharmony_cistatic inline void toggle_TACK(void) 13562306a36Sopenharmony_ci{ 13662306a36Sopenharmony_ci out_8(&via[B], in_8(&via[B]) ^ TACK); 13762306a36Sopenharmony_ci} 13862306a36Sopenharmony_ci 13962306a36Sopenharmony_cistatic inline void negate_TACK(void) 14062306a36Sopenharmony_ci{ 14162306a36Sopenharmony_ci if (mcu_is_egret) { 14262306a36Sopenharmony_ci udelay(EGRET_TACK_ASSERTED_DELAY); 14362306a36Sopenharmony_ci out_8(&via[B], in_8(&via[B]) & ~TACK); 14462306a36Sopenharmony_ci } else 14562306a36Sopenharmony_ci out_8(&via[B], in_8(&via[B]) | TACK); 14662306a36Sopenharmony_ci} 14762306a36Sopenharmony_ci 14862306a36Sopenharmony_cistatic inline void negate_TIP_and_TACK(void) 14962306a36Sopenharmony_ci{ 15062306a36Sopenharmony_ci if (mcu_is_egret) { 15162306a36Sopenharmony_ci udelay(EGRET_TACK_ASSERTED_DELAY); 15262306a36Sopenharmony_ci out_8(&via[B], in_8(&via[B]) & ~(TIP | TACK)); 15362306a36Sopenharmony_ci } else 15462306a36Sopenharmony_ci out_8(&via[B], in_8(&via[B]) | TIP | TACK); 15562306a36Sopenharmony_ci} 15662306a36Sopenharmony_ci 15762306a36Sopenharmony_cistatic enum cuda_state { 15862306a36Sopenharmony_ci idle, 15962306a36Sopenharmony_ci sent_first_byte, 16062306a36Sopenharmony_ci sending, 16162306a36Sopenharmony_ci reading, 16262306a36Sopenharmony_ci read_done, 16362306a36Sopenharmony_ci awaiting_reply 16462306a36Sopenharmony_ci} cuda_state; 16562306a36Sopenharmony_ci 16662306a36Sopenharmony_cistatic struct adb_request *current_req; 16762306a36Sopenharmony_cistatic struct adb_request *last_req; 16862306a36Sopenharmony_cistatic unsigned char cuda_rbuf[16]; 16962306a36Sopenharmony_cistatic unsigned char *reply_ptr; 17062306a36Sopenharmony_cistatic int reading_reply; 17162306a36Sopenharmony_cistatic int data_index; 17262306a36Sopenharmony_cistatic int cuda_irq; 17362306a36Sopenharmony_ci#ifdef CONFIG_PPC 17462306a36Sopenharmony_cistatic struct device_node *vias; 17562306a36Sopenharmony_ci#endif 17662306a36Sopenharmony_cistatic int cuda_fully_inited; 17762306a36Sopenharmony_ci 17862306a36Sopenharmony_ci#ifdef CONFIG_ADB 17962306a36Sopenharmony_cistatic int cuda_probe(void); 18062306a36Sopenharmony_cistatic int cuda_send_request(struct adb_request *req, int sync); 18162306a36Sopenharmony_cistatic int cuda_adb_autopoll(int devs); 18262306a36Sopenharmony_cistatic int cuda_reset_adb_bus(void); 18362306a36Sopenharmony_ci#endif /* CONFIG_ADB */ 18462306a36Sopenharmony_ci 18562306a36Sopenharmony_cistatic int cuda_init_via(void); 18662306a36Sopenharmony_cistatic void cuda_start(void); 18762306a36Sopenharmony_cistatic irqreturn_t cuda_interrupt(int irq, void *arg); 18862306a36Sopenharmony_cistatic void cuda_input(unsigned char *buf, int nb); 18962306a36Sopenharmony_civoid cuda_poll(void); 19062306a36Sopenharmony_cistatic int cuda_write(struct adb_request *req); 19162306a36Sopenharmony_ci 19262306a36Sopenharmony_ciint cuda_request(struct adb_request *req, 19362306a36Sopenharmony_ci void (*done)(struct adb_request *), int nbytes, ...); 19462306a36Sopenharmony_ci 19562306a36Sopenharmony_ci#ifdef CONFIG_ADB 19662306a36Sopenharmony_cistruct adb_driver via_cuda_driver = { 19762306a36Sopenharmony_ci .name = "CUDA", 19862306a36Sopenharmony_ci .probe = cuda_probe, 19962306a36Sopenharmony_ci .send_request = cuda_send_request, 20062306a36Sopenharmony_ci .autopoll = cuda_adb_autopoll, 20162306a36Sopenharmony_ci .poll = cuda_poll, 20262306a36Sopenharmony_ci .reset_bus = cuda_reset_adb_bus, 20362306a36Sopenharmony_ci}; 20462306a36Sopenharmony_ci#endif /* CONFIG_ADB */ 20562306a36Sopenharmony_ci 20662306a36Sopenharmony_ci#ifdef CONFIG_MAC 20762306a36Sopenharmony_ciint __init find_via_cuda(void) 20862306a36Sopenharmony_ci{ 20962306a36Sopenharmony_ci struct adb_request req; 21062306a36Sopenharmony_ci int err; 21162306a36Sopenharmony_ci 21262306a36Sopenharmony_ci if (macintosh_config->adb_type != MAC_ADB_CUDA && 21362306a36Sopenharmony_ci macintosh_config->adb_type != MAC_ADB_EGRET) 21462306a36Sopenharmony_ci return 0; 21562306a36Sopenharmony_ci 21662306a36Sopenharmony_ci via = via1; 21762306a36Sopenharmony_ci cuda_state = idle; 21862306a36Sopenharmony_ci mcu_is_egret = macintosh_config->adb_type == MAC_ADB_EGRET; 21962306a36Sopenharmony_ci 22062306a36Sopenharmony_ci err = cuda_init_via(); 22162306a36Sopenharmony_ci if (err) { 22262306a36Sopenharmony_ci printk(KERN_ERR "cuda_init_via() failed\n"); 22362306a36Sopenharmony_ci via = NULL; 22462306a36Sopenharmony_ci return 0; 22562306a36Sopenharmony_ci } 22662306a36Sopenharmony_ci 22762306a36Sopenharmony_ci /* enable autopoll */ 22862306a36Sopenharmony_ci cuda_request(&req, NULL, 3, CUDA_PACKET, CUDA_AUTOPOLL, 1); 22962306a36Sopenharmony_ci while (!req.complete) 23062306a36Sopenharmony_ci cuda_poll(); 23162306a36Sopenharmony_ci 23262306a36Sopenharmony_ci return 1; 23362306a36Sopenharmony_ci} 23462306a36Sopenharmony_ci#else 23562306a36Sopenharmony_ciint __init find_via_cuda(void) 23662306a36Sopenharmony_ci{ 23762306a36Sopenharmony_ci struct adb_request req; 23862306a36Sopenharmony_ci struct resource res; 23962306a36Sopenharmony_ci int err; 24062306a36Sopenharmony_ci 24162306a36Sopenharmony_ci if (vias) 24262306a36Sopenharmony_ci return 1; 24362306a36Sopenharmony_ci vias = of_find_node_by_name(NULL, "via-cuda"); 24462306a36Sopenharmony_ci if (!vias) 24562306a36Sopenharmony_ci return 0; 24662306a36Sopenharmony_ci 24762306a36Sopenharmony_ci err = of_address_to_resource(vias, 0, &res); 24862306a36Sopenharmony_ci if (err) { 24962306a36Sopenharmony_ci printk(KERN_ERR "via-cuda: Error getting \"reg\" property !\n"); 25062306a36Sopenharmony_ci goto fail; 25162306a36Sopenharmony_ci } 25262306a36Sopenharmony_ci via = ioremap(res.start, 0x2000); 25362306a36Sopenharmony_ci if (via == NULL) { 25462306a36Sopenharmony_ci printk(KERN_ERR "via-cuda: Can't map address !\n"); 25562306a36Sopenharmony_ci goto fail; 25662306a36Sopenharmony_ci } 25762306a36Sopenharmony_ci 25862306a36Sopenharmony_ci cuda_state = idle; 25962306a36Sopenharmony_ci sys_ctrler = SYS_CTRLER_CUDA; 26062306a36Sopenharmony_ci 26162306a36Sopenharmony_ci err = cuda_init_via(); 26262306a36Sopenharmony_ci if (err) { 26362306a36Sopenharmony_ci printk(KERN_ERR "cuda_init_via() failed\n"); 26462306a36Sopenharmony_ci via = NULL; 26562306a36Sopenharmony_ci return 0; 26662306a36Sopenharmony_ci } 26762306a36Sopenharmony_ci 26862306a36Sopenharmony_ci /* Clear and enable interrupts, but only on PPC. On 68K it's done */ 26962306a36Sopenharmony_ci /* for us by the main VIA driver in arch/m68k/mac/via.c */ 27062306a36Sopenharmony_ci 27162306a36Sopenharmony_ci out_8(&via[IFR], 0x7f); /* clear interrupts by writing 1s */ 27262306a36Sopenharmony_ci out_8(&via[IER], IER_SET|SR_INT); /* enable interrupt from SR */ 27362306a36Sopenharmony_ci 27462306a36Sopenharmony_ci /* enable autopoll */ 27562306a36Sopenharmony_ci cuda_request(&req, NULL, 3, CUDA_PACKET, CUDA_AUTOPOLL, 1); 27662306a36Sopenharmony_ci while (!req.complete) 27762306a36Sopenharmony_ci cuda_poll(); 27862306a36Sopenharmony_ci 27962306a36Sopenharmony_ci return 1; 28062306a36Sopenharmony_ci 28162306a36Sopenharmony_ci fail: 28262306a36Sopenharmony_ci of_node_put(vias); 28362306a36Sopenharmony_ci vias = NULL; 28462306a36Sopenharmony_ci return 0; 28562306a36Sopenharmony_ci} 28662306a36Sopenharmony_ci#endif /* !defined CONFIG_MAC */ 28762306a36Sopenharmony_ci 28862306a36Sopenharmony_cistatic int __init via_cuda_start(void) 28962306a36Sopenharmony_ci{ 29062306a36Sopenharmony_ci if (via == NULL) 29162306a36Sopenharmony_ci return -ENODEV; 29262306a36Sopenharmony_ci 29362306a36Sopenharmony_ci#ifdef CONFIG_MAC 29462306a36Sopenharmony_ci cuda_irq = IRQ_MAC_ADB; 29562306a36Sopenharmony_ci#else 29662306a36Sopenharmony_ci cuda_irq = irq_of_parse_and_map(vias, 0); 29762306a36Sopenharmony_ci if (!cuda_irq) { 29862306a36Sopenharmony_ci printk(KERN_ERR "via-cuda: can't map interrupts for %pOF\n", 29962306a36Sopenharmony_ci vias); 30062306a36Sopenharmony_ci return -ENODEV; 30162306a36Sopenharmony_ci } 30262306a36Sopenharmony_ci#endif 30362306a36Sopenharmony_ci 30462306a36Sopenharmony_ci if (request_irq(cuda_irq, cuda_interrupt, 0, "ADB", cuda_interrupt)) { 30562306a36Sopenharmony_ci printk(KERN_ERR "via-cuda: can't request irq %d\n", cuda_irq); 30662306a36Sopenharmony_ci return -EAGAIN; 30762306a36Sopenharmony_ci } 30862306a36Sopenharmony_ci 30962306a36Sopenharmony_ci pr_info("Macintosh Cuda and Egret driver.\n"); 31062306a36Sopenharmony_ci 31162306a36Sopenharmony_ci cuda_fully_inited = 1; 31262306a36Sopenharmony_ci return 0; 31362306a36Sopenharmony_ci} 31462306a36Sopenharmony_ci 31562306a36Sopenharmony_cidevice_initcall(via_cuda_start); 31662306a36Sopenharmony_ci 31762306a36Sopenharmony_ci#ifdef CONFIG_ADB 31862306a36Sopenharmony_cistatic int 31962306a36Sopenharmony_cicuda_probe(void) 32062306a36Sopenharmony_ci{ 32162306a36Sopenharmony_ci#ifdef CONFIG_PPC 32262306a36Sopenharmony_ci if (sys_ctrler != SYS_CTRLER_CUDA) 32362306a36Sopenharmony_ci return -ENODEV; 32462306a36Sopenharmony_ci#else 32562306a36Sopenharmony_ci if (macintosh_config->adb_type != MAC_ADB_CUDA && 32662306a36Sopenharmony_ci macintosh_config->adb_type != MAC_ADB_EGRET) 32762306a36Sopenharmony_ci return -ENODEV; 32862306a36Sopenharmony_ci#endif 32962306a36Sopenharmony_ci if (via == NULL) 33062306a36Sopenharmony_ci return -ENODEV; 33162306a36Sopenharmony_ci return 0; 33262306a36Sopenharmony_ci} 33362306a36Sopenharmony_ci#endif /* CONFIG_ADB */ 33462306a36Sopenharmony_ci 33562306a36Sopenharmony_cistatic int __init sync_egret(void) 33662306a36Sopenharmony_ci{ 33762306a36Sopenharmony_ci if (TREQ_asserted(in_8(&via[B]))) { 33862306a36Sopenharmony_ci /* Complete the inbound transfer */ 33962306a36Sopenharmony_ci assert_TIP_and_TACK(); 34062306a36Sopenharmony_ci while (1) { 34162306a36Sopenharmony_ci negate_TACK(); 34262306a36Sopenharmony_ci mdelay(1); 34362306a36Sopenharmony_ci (void)in_8(&via[SR]); 34462306a36Sopenharmony_ci assert_TACK(); 34562306a36Sopenharmony_ci if (!TREQ_asserted(in_8(&via[B]))) 34662306a36Sopenharmony_ci break; 34762306a36Sopenharmony_ci } 34862306a36Sopenharmony_ci negate_TIP_and_TACK(); 34962306a36Sopenharmony_ci } else if (in_8(&via[B]) & TIP) { 35062306a36Sopenharmony_ci /* Terminate the outbound transfer */ 35162306a36Sopenharmony_ci negate_TACK(); 35262306a36Sopenharmony_ci assert_TACK(); 35362306a36Sopenharmony_ci mdelay(1); 35462306a36Sopenharmony_ci negate_TIP_and_TACK(); 35562306a36Sopenharmony_ci } 35662306a36Sopenharmony_ci /* Clear shift register interrupt */ 35762306a36Sopenharmony_ci if (in_8(&via[IFR]) & SR_INT) 35862306a36Sopenharmony_ci (void)in_8(&via[SR]); 35962306a36Sopenharmony_ci return 0; 36062306a36Sopenharmony_ci} 36162306a36Sopenharmony_ci 36262306a36Sopenharmony_ci#define WAIT_FOR(cond, what) \ 36362306a36Sopenharmony_ci do { \ 36462306a36Sopenharmony_ci int x; \ 36562306a36Sopenharmony_ci for (x = 1000; !(cond); --x) { \ 36662306a36Sopenharmony_ci if (x == 0) { \ 36762306a36Sopenharmony_ci pr_err("Timeout waiting for " what "\n"); \ 36862306a36Sopenharmony_ci return -ENXIO; \ 36962306a36Sopenharmony_ci } \ 37062306a36Sopenharmony_ci udelay(100); \ 37162306a36Sopenharmony_ci } \ 37262306a36Sopenharmony_ci } while (0) 37362306a36Sopenharmony_ci 37462306a36Sopenharmony_cistatic int 37562306a36Sopenharmony_ci__init cuda_init_via(void) 37662306a36Sopenharmony_ci{ 37762306a36Sopenharmony_ci#ifdef CONFIG_PPC 37862306a36Sopenharmony_ci out_8(&via[IER], 0x7f); /* disable interrupts from VIA */ 37962306a36Sopenharmony_ci (void)in_8(&via[IER]); 38062306a36Sopenharmony_ci#else 38162306a36Sopenharmony_ci out_8(&via[IER], SR_INT); /* disable SR interrupt from VIA */ 38262306a36Sopenharmony_ci#endif 38362306a36Sopenharmony_ci 38462306a36Sopenharmony_ci out_8(&via[DIRB], (in_8(&via[DIRB]) | TACK | TIP) & ~TREQ); /* TACK & TIP out */ 38562306a36Sopenharmony_ci out_8(&via[ACR], (in_8(&via[ACR]) & ~SR_CTRL) | SR_EXT); /* SR data in */ 38662306a36Sopenharmony_ci (void)in_8(&via[SR]); /* clear any left-over data */ 38762306a36Sopenharmony_ci 38862306a36Sopenharmony_ci if (mcu_is_egret) 38962306a36Sopenharmony_ci return sync_egret(); 39062306a36Sopenharmony_ci 39162306a36Sopenharmony_ci negate_TIP_and_TACK(); 39262306a36Sopenharmony_ci 39362306a36Sopenharmony_ci /* delay 4ms and then clear any pending interrupt */ 39462306a36Sopenharmony_ci mdelay(4); 39562306a36Sopenharmony_ci (void)in_8(&via[SR]); 39662306a36Sopenharmony_ci out_8(&via[IFR], SR_INT); 39762306a36Sopenharmony_ci 39862306a36Sopenharmony_ci /* sync with the CUDA - assert TACK without TIP */ 39962306a36Sopenharmony_ci assert_TACK(); 40062306a36Sopenharmony_ci 40162306a36Sopenharmony_ci /* wait for the CUDA to assert TREQ in response */ 40262306a36Sopenharmony_ci WAIT_FOR(TREQ_asserted(in_8(&via[B])), "CUDA response to sync"); 40362306a36Sopenharmony_ci 40462306a36Sopenharmony_ci /* wait for the interrupt and then clear it */ 40562306a36Sopenharmony_ci WAIT_FOR(in_8(&via[IFR]) & SR_INT, "CUDA response to sync (2)"); 40662306a36Sopenharmony_ci (void)in_8(&via[SR]); 40762306a36Sopenharmony_ci out_8(&via[IFR], SR_INT); 40862306a36Sopenharmony_ci 40962306a36Sopenharmony_ci /* finish the sync by negating TACK */ 41062306a36Sopenharmony_ci negate_TACK(); 41162306a36Sopenharmony_ci 41262306a36Sopenharmony_ci /* wait for the CUDA to negate TREQ and the corresponding interrupt */ 41362306a36Sopenharmony_ci WAIT_FOR(!TREQ_asserted(in_8(&via[B])), "CUDA response to sync (3)"); 41462306a36Sopenharmony_ci WAIT_FOR(in_8(&via[IFR]) & SR_INT, "CUDA response to sync (4)"); 41562306a36Sopenharmony_ci (void)in_8(&via[SR]); 41662306a36Sopenharmony_ci out_8(&via[IFR], SR_INT); 41762306a36Sopenharmony_ci 41862306a36Sopenharmony_ci return 0; 41962306a36Sopenharmony_ci} 42062306a36Sopenharmony_ci 42162306a36Sopenharmony_ci#ifdef CONFIG_ADB 42262306a36Sopenharmony_ci/* Send an ADB command */ 42362306a36Sopenharmony_cistatic int 42462306a36Sopenharmony_cicuda_send_request(struct adb_request *req, int sync) 42562306a36Sopenharmony_ci{ 42662306a36Sopenharmony_ci int i; 42762306a36Sopenharmony_ci 42862306a36Sopenharmony_ci if ((via == NULL) || !cuda_fully_inited) { 42962306a36Sopenharmony_ci req->complete = 1; 43062306a36Sopenharmony_ci return -ENXIO; 43162306a36Sopenharmony_ci } 43262306a36Sopenharmony_ci 43362306a36Sopenharmony_ci req->reply_expected = 1; 43462306a36Sopenharmony_ci 43562306a36Sopenharmony_ci i = cuda_write(req); 43662306a36Sopenharmony_ci if (i) 43762306a36Sopenharmony_ci return i; 43862306a36Sopenharmony_ci 43962306a36Sopenharmony_ci if (sync) { 44062306a36Sopenharmony_ci while (!req->complete) 44162306a36Sopenharmony_ci cuda_poll(); 44262306a36Sopenharmony_ci } 44362306a36Sopenharmony_ci return 0; 44462306a36Sopenharmony_ci} 44562306a36Sopenharmony_ci 44662306a36Sopenharmony_ci 44762306a36Sopenharmony_ci/* Enable/disable autopolling */ 44862306a36Sopenharmony_cistatic int 44962306a36Sopenharmony_cicuda_adb_autopoll(int devs) 45062306a36Sopenharmony_ci{ 45162306a36Sopenharmony_ci struct adb_request req; 45262306a36Sopenharmony_ci 45362306a36Sopenharmony_ci if ((via == NULL) || !cuda_fully_inited) 45462306a36Sopenharmony_ci return -ENXIO; 45562306a36Sopenharmony_ci 45662306a36Sopenharmony_ci cuda_request(&req, NULL, 3, CUDA_PACKET, CUDA_AUTOPOLL, (devs? 1: 0)); 45762306a36Sopenharmony_ci while (!req.complete) 45862306a36Sopenharmony_ci cuda_poll(); 45962306a36Sopenharmony_ci return 0; 46062306a36Sopenharmony_ci} 46162306a36Sopenharmony_ci 46262306a36Sopenharmony_ci/* Reset adb bus - how do we do this?? */ 46362306a36Sopenharmony_cistatic int 46462306a36Sopenharmony_cicuda_reset_adb_bus(void) 46562306a36Sopenharmony_ci{ 46662306a36Sopenharmony_ci struct adb_request req; 46762306a36Sopenharmony_ci 46862306a36Sopenharmony_ci if ((via == NULL) || !cuda_fully_inited) 46962306a36Sopenharmony_ci return -ENXIO; 47062306a36Sopenharmony_ci 47162306a36Sopenharmony_ci cuda_request(&req, NULL, 2, ADB_PACKET, 0); /* maybe? */ 47262306a36Sopenharmony_ci while (!req.complete) 47362306a36Sopenharmony_ci cuda_poll(); 47462306a36Sopenharmony_ci return 0; 47562306a36Sopenharmony_ci} 47662306a36Sopenharmony_ci#endif /* CONFIG_ADB */ 47762306a36Sopenharmony_ci 47862306a36Sopenharmony_ci/* Construct and send a cuda request */ 47962306a36Sopenharmony_ciint 48062306a36Sopenharmony_cicuda_request(struct adb_request *req, void (*done)(struct adb_request *), 48162306a36Sopenharmony_ci int nbytes, ...) 48262306a36Sopenharmony_ci{ 48362306a36Sopenharmony_ci va_list list; 48462306a36Sopenharmony_ci int i; 48562306a36Sopenharmony_ci 48662306a36Sopenharmony_ci if (via == NULL) { 48762306a36Sopenharmony_ci req->complete = 1; 48862306a36Sopenharmony_ci return -ENXIO; 48962306a36Sopenharmony_ci } 49062306a36Sopenharmony_ci 49162306a36Sopenharmony_ci req->nbytes = nbytes; 49262306a36Sopenharmony_ci req->done = done; 49362306a36Sopenharmony_ci va_start(list, nbytes); 49462306a36Sopenharmony_ci for (i = 0; i < nbytes; ++i) 49562306a36Sopenharmony_ci req->data[i] = va_arg(list, int); 49662306a36Sopenharmony_ci va_end(list); 49762306a36Sopenharmony_ci req->reply_expected = 1; 49862306a36Sopenharmony_ci return cuda_write(req); 49962306a36Sopenharmony_ci} 50062306a36Sopenharmony_ciEXPORT_SYMBOL(cuda_request); 50162306a36Sopenharmony_ci 50262306a36Sopenharmony_cistatic int 50362306a36Sopenharmony_cicuda_write(struct adb_request *req) 50462306a36Sopenharmony_ci{ 50562306a36Sopenharmony_ci unsigned long flags; 50662306a36Sopenharmony_ci 50762306a36Sopenharmony_ci if (req->nbytes < 2 || req->data[0] > CUDA_PACKET) { 50862306a36Sopenharmony_ci req->complete = 1; 50962306a36Sopenharmony_ci return -EINVAL; 51062306a36Sopenharmony_ci } 51162306a36Sopenharmony_ci req->next = NULL; 51262306a36Sopenharmony_ci req->sent = 0; 51362306a36Sopenharmony_ci req->complete = 0; 51462306a36Sopenharmony_ci req->reply_len = 0; 51562306a36Sopenharmony_ci 51662306a36Sopenharmony_ci spin_lock_irqsave(&cuda_lock, flags); 51762306a36Sopenharmony_ci if (current_req) { 51862306a36Sopenharmony_ci last_req->next = req; 51962306a36Sopenharmony_ci last_req = req; 52062306a36Sopenharmony_ci } else { 52162306a36Sopenharmony_ci current_req = req; 52262306a36Sopenharmony_ci last_req = req; 52362306a36Sopenharmony_ci if (cuda_state == idle) 52462306a36Sopenharmony_ci cuda_start(); 52562306a36Sopenharmony_ci } 52662306a36Sopenharmony_ci spin_unlock_irqrestore(&cuda_lock, flags); 52762306a36Sopenharmony_ci 52862306a36Sopenharmony_ci return 0; 52962306a36Sopenharmony_ci} 53062306a36Sopenharmony_ci 53162306a36Sopenharmony_cistatic void 53262306a36Sopenharmony_cicuda_start(void) 53362306a36Sopenharmony_ci{ 53462306a36Sopenharmony_ci /* assert cuda_state == idle */ 53562306a36Sopenharmony_ci if (current_req == NULL) 53662306a36Sopenharmony_ci return; 53762306a36Sopenharmony_ci data_index = 0; 53862306a36Sopenharmony_ci if (TREQ_asserted(in_8(&via[B]))) 53962306a36Sopenharmony_ci return; /* a byte is coming in from the CUDA */ 54062306a36Sopenharmony_ci 54162306a36Sopenharmony_ci /* set the shift register to shift out and send a byte */ 54262306a36Sopenharmony_ci out_8(&via[ACR], in_8(&via[ACR]) | SR_OUT); 54362306a36Sopenharmony_ci out_8(&via[SR], current_req->data[data_index++]); 54462306a36Sopenharmony_ci if (mcu_is_egret) 54562306a36Sopenharmony_ci assert_TIP_and_TACK(); 54662306a36Sopenharmony_ci else 54762306a36Sopenharmony_ci assert_TIP(); 54862306a36Sopenharmony_ci cuda_state = sent_first_byte; 54962306a36Sopenharmony_ci} 55062306a36Sopenharmony_ci 55162306a36Sopenharmony_civoid 55262306a36Sopenharmony_cicuda_poll(void) 55362306a36Sopenharmony_ci{ 55462306a36Sopenharmony_ci cuda_interrupt(0, NULL); 55562306a36Sopenharmony_ci} 55662306a36Sopenharmony_ciEXPORT_SYMBOL(cuda_poll); 55762306a36Sopenharmony_ci 55862306a36Sopenharmony_ci#define ARRAY_FULL(a, p) ((p) - (a) == ARRAY_SIZE(a)) 55962306a36Sopenharmony_ci 56062306a36Sopenharmony_cistatic irqreturn_t 56162306a36Sopenharmony_cicuda_interrupt(int irq, void *arg) 56262306a36Sopenharmony_ci{ 56362306a36Sopenharmony_ci unsigned long flags; 56462306a36Sopenharmony_ci u8 status; 56562306a36Sopenharmony_ci struct adb_request *req = NULL; 56662306a36Sopenharmony_ci unsigned char ibuf[16]; 56762306a36Sopenharmony_ci int ibuf_len = 0; 56862306a36Sopenharmony_ci int complete = 0; 56962306a36Sopenharmony_ci bool full; 57062306a36Sopenharmony_ci 57162306a36Sopenharmony_ci spin_lock_irqsave(&cuda_lock, flags); 57262306a36Sopenharmony_ci 57362306a36Sopenharmony_ci /* On powermacs, this handler is registered for the VIA IRQ. But they use 57462306a36Sopenharmony_ci * just the shift register IRQ -- other VIA interrupt sources are disabled. 57562306a36Sopenharmony_ci * On m68k macs, the VIA IRQ sources are dispatched individually. Unless 57662306a36Sopenharmony_ci * we are polling, the shift register IRQ flag has already been cleared. 57762306a36Sopenharmony_ci */ 57862306a36Sopenharmony_ci 57962306a36Sopenharmony_ci#ifdef CONFIG_MAC 58062306a36Sopenharmony_ci if (!arg) 58162306a36Sopenharmony_ci#endif 58262306a36Sopenharmony_ci { 58362306a36Sopenharmony_ci if ((in_8(&via[IFR]) & SR_INT) == 0) { 58462306a36Sopenharmony_ci spin_unlock_irqrestore(&cuda_lock, flags); 58562306a36Sopenharmony_ci return IRQ_NONE; 58662306a36Sopenharmony_ci } else { 58762306a36Sopenharmony_ci out_8(&via[IFR], SR_INT); 58862306a36Sopenharmony_ci } 58962306a36Sopenharmony_ci } 59062306a36Sopenharmony_ci 59162306a36Sopenharmony_ci status = in_8(&via[B]) & (TIP | TACK | TREQ); 59262306a36Sopenharmony_ci 59362306a36Sopenharmony_ci switch (cuda_state) { 59462306a36Sopenharmony_ci case idle: 59562306a36Sopenharmony_ci /* System controller has unsolicited data for us */ 59662306a36Sopenharmony_ci (void)in_8(&via[SR]); 59762306a36Sopenharmony_ciidle_state: 59862306a36Sopenharmony_ci assert_TIP(); 59962306a36Sopenharmony_ci cuda_state = reading; 60062306a36Sopenharmony_ci reply_ptr = cuda_rbuf; 60162306a36Sopenharmony_ci reading_reply = 0; 60262306a36Sopenharmony_ci break; 60362306a36Sopenharmony_ci 60462306a36Sopenharmony_ci case awaiting_reply: 60562306a36Sopenharmony_ci /* System controller has reply data for us */ 60662306a36Sopenharmony_ci (void)in_8(&via[SR]); 60762306a36Sopenharmony_ci assert_TIP(); 60862306a36Sopenharmony_ci cuda_state = reading; 60962306a36Sopenharmony_ci reply_ptr = current_req->reply; 61062306a36Sopenharmony_ci reading_reply = 1; 61162306a36Sopenharmony_ci break; 61262306a36Sopenharmony_ci 61362306a36Sopenharmony_ci case sent_first_byte: 61462306a36Sopenharmony_ci if (TREQ_asserted(status)) { 61562306a36Sopenharmony_ci /* collision */ 61662306a36Sopenharmony_ci out_8(&via[ACR], in_8(&via[ACR]) & ~SR_OUT); 61762306a36Sopenharmony_ci (void)in_8(&via[SR]); 61862306a36Sopenharmony_ci negate_TIP_and_TACK(); 61962306a36Sopenharmony_ci cuda_state = idle; 62062306a36Sopenharmony_ci /* Egret does not raise an "aborted" interrupt */ 62162306a36Sopenharmony_ci if (mcu_is_egret) 62262306a36Sopenharmony_ci goto idle_state; 62362306a36Sopenharmony_ci } else { 62462306a36Sopenharmony_ci out_8(&via[SR], current_req->data[data_index++]); 62562306a36Sopenharmony_ci toggle_TACK(); 62662306a36Sopenharmony_ci if (mcu_is_egret) 62762306a36Sopenharmony_ci assert_TACK(); 62862306a36Sopenharmony_ci cuda_state = sending; 62962306a36Sopenharmony_ci } 63062306a36Sopenharmony_ci break; 63162306a36Sopenharmony_ci 63262306a36Sopenharmony_ci case sending: 63362306a36Sopenharmony_ci req = current_req; 63462306a36Sopenharmony_ci if (data_index >= req->nbytes) { 63562306a36Sopenharmony_ci out_8(&via[ACR], in_8(&via[ACR]) & ~SR_OUT); 63662306a36Sopenharmony_ci (void)in_8(&via[SR]); 63762306a36Sopenharmony_ci negate_TIP_and_TACK(); 63862306a36Sopenharmony_ci req->sent = 1; 63962306a36Sopenharmony_ci if (req->reply_expected) { 64062306a36Sopenharmony_ci cuda_state = awaiting_reply; 64162306a36Sopenharmony_ci } else { 64262306a36Sopenharmony_ci current_req = req->next; 64362306a36Sopenharmony_ci complete = 1; 64462306a36Sopenharmony_ci /* not sure about this */ 64562306a36Sopenharmony_ci cuda_state = idle; 64662306a36Sopenharmony_ci cuda_start(); 64762306a36Sopenharmony_ci } 64862306a36Sopenharmony_ci } else { 64962306a36Sopenharmony_ci out_8(&via[SR], req->data[data_index++]); 65062306a36Sopenharmony_ci toggle_TACK(); 65162306a36Sopenharmony_ci if (mcu_is_egret) 65262306a36Sopenharmony_ci assert_TACK(); 65362306a36Sopenharmony_ci } 65462306a36Sopenharmony_ci break; 65562306a36Sopenharmony_ci 65662306a36Sopenharmony_ci case reading: 65762306a36Sopenharmony_ci full = reading_reply ? ARRAY_FULL(current_req->reply, reply_ptr) 65862306a36Sopenharmony_ci : ARRAY_FULL(cuda_rbuf, reply_ptr); 65962306a36Sopenharmony_ci if (full) 66062306a36Sopenharmony_ci (void)in_8(&via[SR]); 66162306a36Sopenharmony_ci else 66262306a36Sopenharmony_ci *reply_ptr++ = in_8(&via[SR]); 66362306a36Sopenharmony_ci if (!TREQ_asserted(status) || full) { 66462306a36Sopenharmony_ci if (mcu_is_egret) 66562306a36Sopenharmony_ci assert_TACK(); 66662306a36Sopenharmony_ci /* that's all folks */ 66762306a36Sopenharmony_ci negate_TIP_and_TACK(); 66862306a36Sopenharmony_ci cuda_state = read_done; 66962306a36Sopenharmony_ci /* Egret does not raise a "read done" interrupt */ 67062306a36Sopenharmony_ci if (mcu_is_egret) 67162306a36Sopenharmony_ci goto read_done_state; 67262306a36Sopenharmony_ci } else { 67362306a36Sopenharmony_ci toggle_TACK(); 67462306a36Sopenharmony_ci if (mcu_is_egret) 67562306a36Sopenharmony_ci negate_TACK(); 67662306a36Sopenharmony_ci } 67762306a36Sopenharmony_ci break; 67862306a36Sopenharmony_ci 67962306a36Sopenharmony_ci case read_done: 68062306a36Sopenharmony_ci (void)in_8(&via[SR]); 68162306a36Sopenharmony_ciread_done_state: 68262306a36Sopenharmony_ci if (reading_reply) { 68362306a36Sopenharmony_ci req = current_req; 68462306a36Sopenharmony_ci req->reply_len = reply_ptr - req->reply; 68562306a36Sopenharmony_ci if (req->data[0] == ADB_PACKET) { 68662306a36Sopenharmony_ci /* Have to adjust the reply from ADB commands */ 68762306a36Sopenharmony_ci if (req->reply_len <= 2 || (req->reply[1] & 2) != 0) { 68862306a36Sopenharmony_ci /* the 0x2 bit indicates no response */ 68962306a36Sopenharmony_ci req->reply_len = 0; 69062306a36Sopenharmony_ci } else { 69162306a36Sopenharmony_ci /* leave just the command and result bytes in the reply */ 69262306a36Sopenharmony_ci req->reply_len -= 2; 69362306a36Sopenharmony_ci memmove(req->reply, req->reply + 2, req->reply_len); 69462306a36Sopenharmony_ci } 69562306a36Sopenharmony_ci } 69662306a36Sopenharmony_ci current_req = req->next; 69762306a36Sopenharmony_ci complete = 1; 69862306a36Sopenharmony_ci reading_reply = 0; 69962306a36Sopenharmony_ci } else { 70062306a36Sopenharmony_ci /* This is tricky. We must break the spinlock to call 70162306a36Sopenharmony_ci * cuda_input. However, doing so means we might get 70262306a36Sopenharmony_ci * re-entered from another CPU getting an interrupt 70362306a36Sopenharmony_ci * or calling cuda_poll(). I ended up using the stack 70462306a36Sopenharmony_ci * (it's only for 16 bytes) and moving the actual 70562306a36Sopenharmony_ci * call to cuda_input to outside of the lock. 70662306a36Sopenharmony_ci */ 70762306a36Sopenharmony_ci ibuf_len = reply_ptr - cuda_rbuf; 70862306a36Sopenharmony_ci memcpy(ibuf, cuda_rbuf, ibuf_len); 70962306a36Sopenharmony_ci } 71062306a36Sopenharmony_ci reply_ptr = cuda_rbuf; 71162306a36Sopenharmony_ci cuda_state = idle; 71262306a36Sopenharmony_ci cuda_start(); 71362306a36Sopenharmony_ci if (cuda_state == idle && TREQ_asserted(in_8(&via[B]))) { 71462306a36Sopenharmony_ci assert_TIP(); 71562306a36Sopenharmony_ci cuda_state = reading; 71662306a36Sopenharmony_ci } 71762306a36Sopenharmony_ci break; 71862306a36Sopenharmony_ci 71962306a36Sopenharmony_ci default: 72062306a36Sopenharmony_ci pr_err("cuda_interrupt: unknown cuda_state %d?\n", cuda_state); 72162306a36Sopenharmony_ci } 72262306a36Sopenharmony_ci spin_unlock_irqrestore(&cuda_lock, flags); 72362306a36Sopenharmony_ci if (complete && req) { 72462306a36Sopenharmony_ci void (*done)(struct adb_request *) = req->done; 72562306a36Sopenharmony_ci mb(); 72662306a36Sopenharmony_ci req->complete = 1; 72762306a36Sopenharmony_ci /* Here, we assume that if the request has a done member, the 72862306a36Sopenharmony_ci * struct request will survive to setting req->complete to 1 72962306a36Sopenharmony_ci */ 73062306a36Sopenharmony_ci if (done) 73162306a36Sopenharmony_ci (*done)(req); 73262306a36Sopenharmony_ci } 73362306a36Sopenharmony_ci if (ibuf_len) 73462306a36Sopenharmony_ci cuda_input(ibuf, ibuf_len); 73562306a36Sopenharmony_ci return IRQ_HANDLED; 73662306a36Sopenharmony_ci} 73762306a36Sopenharmony_ci 73862306a36Sopenharmony_cistatic void 73962306a36Sopenharmony_cicuda_input(unsigned char *buf, int nb) 74062306a36Sopenharmony_ci{ 74162306a36Sopenharmony_ci switch (buf[0]) { 74262306a36Sopenharmony_ci case ADB_PACKET: 74362306a36Sopenharmony_ci#ifdef CONFIG_XMON 74462306a36Sopenharmony_ci if (nb == 5 && buf[2] == 0x2c) { 74562306a36Sopenharmony_ci extern int xmon_wants_key, xmon_adb_keycode; 74662306a36Sopenharmony_ci if (xmon_wants_key) { 74762306a36Sopenharmony_ci xmon_adb_keycode = buf[3]; 74862306a36Sopenharmony_ci return; 74962306a36Sopenharmony_ci } 75062306a36Sopenharmony_ci } 75162306a36Sopenharmony_ci#endif /* CONFIG_XMON */ 75262306a36Sopenharmony_ci#ifdef CONFIG_ADB 75362306a36Sopenharmony_ci adb_input(buf+2, nb-2, buf[1] & 0x40); 75462306a36Sopenharmony_ci#endif /* CONFIG_ADB */ 75562306a36Sopenharmony_ci break; 75662306a36Sopenharmony_ci 75762306a36Sopenharmony_ci case TIMER_PACKET: 75862306a36Sopenharmony_ci /* Egret sends these periodically. Might be useful as a 'heartbeat' 75962306a36Sopenharmony_ci * to trigger a recovery for the VIA shift register errata. 76062306a36Sopenharmony_ci */ 76162306a36Sopenharmony_ci break; 76262306a36Sopenharmony_ci 76362306a36Sopenharmony_ci default: 76462306a36Sopenharmony_ci print_hex_dump(KERN_INFO, "cuda_input: ", DUMP_PREFIX_NONE, 32, 1, 76562306a36Sopenharmony_ci buf, nb, false); 76662306a36Sopenharmony_ci } 76762306a36Sopenharmony_ci} 76862306a36Sopenharmony_ci 76962306a36Sopenharmony_ci/* Offset between Unix time (1970-based) and Mac time (1904-based) */ 77062306a36Sopenharmony_ci#define RTC_OFFSET 2082844800 77162306a36Sopenharmony_ci 77262306a36Sopenharmony_citime64_t cuda_get_time(void) 77362306a36Sopenharmony_ci{ 77462306a36Sopenharmony_ci struct adb_request req; 77562306a36Sopenharmony_ci u32 now; 77662306a36Sopenharmony_ci 77762306a36Sopenharmony_ci if (cuda_request(&req, NULL, 2, CUDA_PACKET, CUDA_GET_TIME) < 0) 77862306a36Sopenharmony_ci return 0; 77962306a36Sopenharmony_ci while (!req.complete) 78062306a36Sopenharmony_ci cuda_poll(); 78162306a36Sopenharmony_ci if (req.reply_len != 7) 78262306a36Sopenharmony_ci pr_err("%s: got %d byte reply\n", __func__, req.reply_len); 78362306a36Sopenharmony_ci now = (req.reply[3] << 24) + (req.reply[4] << 16) + 78462306a36Sopenharmony_ci (req.reply[5] << 8) + req.reply[6]; 78562306a36Sopenharmony_ci return (time64_t)now - RTC_OFFSET; 78662306a36Sopenharmony_ci} 78762306a36Sopenharmony_ci 78862306a36Sopenharmony_ciint cuda_set_rtc_time(struct rtc_time *tm) 78962306a36Sopenharmony_ci{ 79062306a36Sopenharmony_ci u32 now; 79162306a36Sopenharmony_ci struct adb_request req; 79262306a36Sopenharmony_ci 79362306a36Sopenharmony_ci now = lower_32_bits(rtc_tm_to_time64(tm) + RTC_OFFSET); 79462306a36Sopenharmony_ci if (cuda_request(&req, NULL, 6, CUDA_PACKET, CUDA_SET_TIME, 79562306a36Sopenharmony_ci now >> 24, now >> 16, now >> 8, now) < 0) 79662306a36Sopenharmony_ci return -ENXIO; 79762306a36Sopenharmony_ci while (!req.complete) 79862306a36Sopenharmony_ci cuda_poll(); 79962306a36Sopenharmony_ci if ((req.reply_len != 3) && (req.reply_len != 7)) 80062306a36Sopenharmony_ci pr_err("%s: got %d byte reply\n", __func__, req.reply_len); 80162306a36Sopenharmony_ci return 0; 80262306a36Sopenharmony_ci} 803